C ++拷贝构造函数调用

时间:2009-11-23 14:12:52

标签: c++

据我所知,在以下场景中调用了复制构造函数:

1) Pass by value
2) Return by value
3) When you create and initialize a new object with an existing object

以下是该计划:

#include <iostream> 
using namespace std; 
class Example 
{ 
    public:
        Example() 
        {
            cout << "Default constructor called.\n";
        }
        Example(const Example &ob1) 
        {
            cout << "Copy constructor called.\n";
        }
        Example& operator=(const Example &ob1) 
        {
            cout << "Assignment operator called.\n"; 
            return *this;
        }
        ~Example()
        {
            cout<<"\nDtor invoked"<<endl;
        }
        int aa;
};

Example funct() 
{
    Example ob2;
    ob2.aa=100;
    return ob2;
}



int main() 
{
    Example x;
    cout << "Calling funct..\n";
    x = funct();
    return 0;
}

输出结果为:

  

默认构造函数。

     

致电功能..

     

默认构造函数。

     

调用分配运算符。

     

Dtor援引

     

Dtor援引

请纠正我,IIRC应该发生以下呼叫顺序:

1)x的构造函数称为

2)ob2的构造函数被称为

3)函数返回,因此调用复制构造函数(将ob2复制到未命名的临时变量,即funct())

4)ob2的析构函数叫

5)将未命名的临时变量分配给x

6)销毁临时变量,即调用其析构函数

7)销毁x,即调用x的析构函数

但是为什么没有调用复制构造函数,也只有2次调用dtors,而我期望3。

我知道编译器可以进行优化,但是,我的理解是否正确?

非常感谢:)

此致

拉​​利

5 个答案:

答案 0 :(得分:11)

按值返回 时,可能无法调用复制构造函数。一些编译器使用返回值优化功能。

  

了解“返回值优化

答案 1 :(得分:4)

标准中告诉您编译器何时可以删除副本的部分是12.8 / 15。始终由编译器决定是否实际执行elision。有两种法律情况,加上它们的任意组合:

  • “在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-nonqualified类型的非易失性自动对象的名称时”

  • “当一个未绑定到引用的临时类对象被复制到具有相同cv-unqualified类型的类对象时”。

前者通常被称为“命名返回值优化”,它允许您在示例中看到的输出。后者实际上将复制初始化转换为直接初始化,例如,如果您的代码执行Example x = Example();,则可能会发生。

除非通常的“假设”规则适用,否则不允许使用其他副本。因此,如果复制构造函数已经跟踪,则以下代码必须调用它:

Example x;
Example y = x;

但是如果x没有被使用,并且cctor没有副作用,那么我认为它可以被优化掉,就像任何其他无效的代码一样。

答案 2 :(得分:2)

做x = funct()时;编译器注意到它将被直接返回,从而避免了无用的构造。这也是为什么你只会得到两个析构函数的调用。

这就是为什么有时候使用“复制”并不一定会失去表演的原因。

答案 3 :(得分:0)

在你的例子中,结构足够小,因此它通过寄存器。生成的代码类似于Return value optimization。构建一个更复杂的示例,您将看到预期的行为。

答案 4 :(得分:0)

g ++ v4.4.1可以选择禁止“删除”优化:


tst@u32-karmic$  g++ -fno-elide-constructors Example.cpp -o Example

tst@u32-karmic$  ./Example 

Default constructor called.
Calling funct..
Default constructor called.

Copy constructor called.

Dtor invoked
Assignment operator called.

Dtor invoked

Dtor invoked

正如您所见,现在调用了复制构造函数!