构造函数的意外行为

时间:2015-02-24 06:33:36

标签: c++

简单程序:

#include <iostream> 

using namespace::std;


class X {
    public:
        X() {
            cout << "Default Constructor called\n";
            i = 0;
        }


        X(int i) {
            cout << "Parameterized Constructor called\n";
            this->i = i;
        }
        X(const X& x) {
            cout << "Copy Constructor called\n";
            i = x.getI();
        }
        ~X() {
            cout << "Destructor called\n";
        }
        int getI() const {
            return i;
        }
        X func() {
            cout << "Entered func\n";
            X x(2);
            return x;
        }
    private:
        int i;
};

int main() {
     X x1;
     X x2 = x1.func();
    cout << "Returned from func\n";    
}

输出以下内容:

Default Constructor called
Entered func
Parameterized Constructor called
Copy Constructor called
Destructor called
Returned from func
Destructor called
Destructor called

我的问题是,在打印'从func返回'之后,在创建实例x2时不会调用构造函数。我实际上期望在实例化x2时调用复制构造函数,就像我们做X x2 = x1;

之类的那样。

1 个答案:

答案 0 :(得分:2)

我最初错误地认为原因是RVO,所以我保留下面的原始答案。

您的程序打印预期。请注意,在调用之后打印“从功能返回”并将返回的值分配给x2。因此打印的顺序是正确的:它首先实例化x,因此参数化ctor调用,然后它将它复制到x2,当它从函数退出时,然后它调用{{1}的析构函数},它不再需要,然后它实际上退出函数,然后才到达你的print语句。

旧答案如下


您观察到的是返回值优化。

  

返回值优化,或简称RVO,是编译器优化   涉及消除创建的临时对象的技术   保持函数的返回值。1在C ++中,它特别值得注意   允许更改结果的可观察行为   方案[2]

  

通常,C ++标准允许编译器执行任何操作   优化,只要生成的可执行文件展示相同   可观察的行为,好像(即假装)所有的要求   标准已经实现。这通常被称为   “as-if rule”。[3]术语返回值优化是指a   C ++标准中的特殊条款甚至超过了   “as-if”规则:实现可能会省略复制操作   从return语句,即使复制构造函数有侧   的效果。[4]

请参阅this wikipedia article,它有一个与您非常相似的示例