【问题标题】:copy constructor being called multiple times c++复制构造函数被多次调用c ++
【发布时间】:2015-08-23 15:00:29
【问题描述】:

我正在阅读 tutorialspoint.com http://www.tutorialspoint.com/cplusplus/cpp_copy_constructor.htm 提供的 C++ 复制构造函数教程

在他们的一个示例代码中:

#include <iostream>

using namespace std;

class Line
{
public:
    int getLength(void);
    Line(int len);          // simple constructor
    Line(const Line &obj);  // copy constructor
    ~Line();                // destructor

private:
    int *ptr;
};

// Member functions definitions including constructor
Line::Line(int len)
{
    cout << "Normal constructor allocating ptr" << endl;
    // allocate memory for the pointer;
    ptr = new int;
    *ptr = len;
}

Line::Line(const Line &obj)
{
    cout << "Copy constructor allocating ptr." << endl;
    ptr = new int;
    *ptr = *obj.ptr; // copy the value
}

Line::~Line(void)
{
    cout << "Freeing memory!" << endl;
    delete ptr;
}

int Line::getLength(void)
{
    return *ptr;
}

void display(Line obj)
{
    cout << "Length of line : " << obj.getLength() << endl;
}

// Main function for the program
int main()
{
    Line line1(10);

    Line line2 = line1; // This also calls copy constructor

    display(line1);
    display(line2);

    return 0;
}

输出是

Normal constructor allocating ptr
Copy constructor allocating ptr.
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!
Freeing memory!

我不明白输出。对我来说,它表明为 line1 调用了普通构造函数,然后为 line2 调用了一个复制构造函数,然后为 2 个对象调用了 2*“释放内存”

我认为的输出是:

Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Length of line : 10
Freeing memory!
Freeing memory!

q.1> 为什么最初多次调用复制构造函数

q.2> 4 次“释放内存”,中间也有 1 次,我真的很困惑,你能帮帮我吗?

谢谢

【问题讨论】:

    标签: c++ copy-constructor


    【解决方案1】:

    这是简单构造的:

    Line line1(10);
    

    正如你所知道的,这是你的复制构造函数被调用的地方:

    Line line2 = line1;
    

    到目前为止一切顺利。现在看看display的签名:

    void display(Line obj);
    

    这就是我们所说的按值传递。 Pass-by-value 是一种参数形式,它导致从传入的对象构造一个新对象。因此,这里的两个调用:

    display(line1);
    display(line2);
    

    都在调用复制构造函数以将line1line2 放入函数局部obj 变量中。

    这大致等价于:

    // Instead of calling display, this happens instead:
    { // Entering a new scope
        Line obj = line1;
        cout << "Length of line : " << obj.getLength() << endl;
    } // Exiting scope
    
    { // Entering a new scope
        Line obj = line2;
        cout << "Length of line : " << obj.getLength() << endl;
    } // Exiting scope
    

    obj 现在是它自己的对象,独立于line1line2 的生命周期,当obj 超出范围时,就像它在函数末尾所做的那样,它的析构函数被调用。这可以解释对析构函数的总共四个调用:一个用于原始简单构造的对象 (line1),一个用于复制构造的对象 (line2),两个用于两个函数本地 objs。

    如果您想避免像您在问题中指出的那样复制,请使用pass-by-reference

    【讨论】:

      【解决方案2】:

      void display(Line obj)为其参数调用复制构造函数,
      您可以使用 const 引用来避免复制 (void display(const Line&amp; obj))。

      【讨论】:

        【解决方案3】:

        示例如下:

        线 line1(10); // 普通构造函数分配ptr

        线 line2 = line1; // 复制构造函数分配ptr

        显示(第 1 行); /* 复制构造函数分配ptr,因为函数是这样的:

        void display(Line obj);

        这将使对象的副本进入方法,就像它是一个 int 一样,例如。如果要消除此副本,请更改为

        void display(const Line& obj);

        传递一个引用。 */

        /* 接下来调用函数并打印

        行长:10

        然后副本的析构函数在函数的末尾被调用,在它返回之前。

        释放内存!

        */

        display(line2);/* 接下来在第二个函数调用中重复相同的模式:

        复制构造函数分配ptr。

        行长:10

        释放内存! */

        返回 0; /* 最后,line1 和 line2 都被销毁:

        释放内存!

        释放内存!

        */

        【讨论】:

          【解决方案4】:

          q.1> 为什么最初多次调用复制构造函数

          您致电display(line)display(line2)void display(Line obj) 被定义为作为参数接收 Line 对象,因此每次调用 display 时,都会为该函数复制该对象(就像您向函数发送整数一样,它的值将被复制,以便如果函数修改了该整数,除了函数的范围外,它不会影响任何东西)。为了减少复制构造函数的数量,您可以将display 定义为void display(Line&amp; obj)。但请注意,对obj 所做的每一次修改都会反映在main() 中。

          q.2>4 次“释放内存”,这也是介于两者之间的,我真的 困惑,你能帮帮我吗?

          两倍于您的预期(一个用于line,另一个用于line2),另外两次用于复制到display 函数的对象。一旦display的流程被执行,它会破坏所有的本地对象,函数参数被认为是一个本地对象。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-07-05
            • 1970-01-01
            • 1970-01-01
            • 2015-04-28
            • 2021-08-06
            相关资源
            最近更新 更多