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

Posted

技术标签:

【中文标题】复制构造函数被多次调用c ++【英文标题】:copy constructor being called multiple times 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 次,我真的很困惑,你能帮帮我吗?

谢谢

【问题讨论】:

【参考方案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的流程被执行,它会破坏所有的本地对象,函数参数被认为是一个本地对象。

【讨论】:

以上是关于复制构造函数被多次调用c ++的主要内容,如果未能解决你的问题,请参考以下文章

c++,类的对象作为形参时一定会调用复制构造函数吗?

c#带参构造函数如何调用?

C ++复制构造函数中的异常[关闭]

C++中复制构造函数被调用的三种情况

复制构造函数与赋值运算符(=)有何不同

复制构造函数不被继承