复制构造函数被多次调用c ++

时间:2015-08-23 15:00:29

标签: c++ copy-constructor

我正在浏览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&GT;为什么复制构造函数最初被多次调用

q.2&gt; 4次“释放记忆”,而且介于两者之间,我真的很困惑,你能帮助我吗?

由于

4 个答案:

答案 0 :(得分:3)

这是简单的构造:

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),两个用于两个函数本地{{ 1}} S上。

如果您想避免在问题中指明的副本,请使用pass-by-reference

答案 1 :(得分:0)

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

答案 2 :(得分:0)

示例如下:

第1行(10); //普通构造函数分配ptr

第2行= line1; //复制构造函数分配ptr

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

void display(Line obj);

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

void display(const Line&amp; obj);

传递参考。 * /

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

行长:10

然后在函数结束时调用副本的析构函数,然后返回。

释放记忆!

* /

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

复制构造函数分配ptr。

行长:10

释放记忆! * /

返回0; / *最后,line1和line2都被破坏了:

释放记忆!

释放记忆!

* /

答案 3 :(得分:0)

  

Q.1&GT;为什么复制构造函数最初被多次调用

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

  

q.2&gt; 4次“释放记忆”,而且介于两者之间,我真的   很困惑,你能救我​​吗?

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