RVO(返回值优化)并不能解释这个谜团

时间:2015-02-24 07:13:10

标签: 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&#39;返回后打印时,在创建实例x2时不会调用构造函数。我实际上期望在实例化x2时调用复制构造函数,就像我们做X x2 = x1;

之类的那样

现在,我被告知这是RVO的结果。这是真的吗?

在wiki中,RVO定义为:

  

返回值优化,或简称为RVO,是一种编译器优化技术,涉及消除为保存函数返回值而创建的临时对象。

但是,我不买这个有两个原因:

1.x2这里不是临时对象。 2.如果确实如此,那么当从函数返回x时,编译器在实现RVO方面要好得多。这是一个临时对象的真实案例(在return语句中)。

因此,请解释为什么在函数返回X对象后未实例化x2。

1 个答案:

答案 0 :(得分:2)

如果您的功能能够输出更准确的信息,那么更容易看到发生了什么。考虑:

#include <iostream>

struct X
{
    X() : i_(0) { std::cout << "X(" << this << ")\n"; }
    X(int i) : i_(i) { std::cout << "X(" << this << ", i " << i << ")\n"; }
    X(const X& rhs) : i_(rhs.i_) { std::cout << "X(" << this << ", const X& "
                                             << &rhs << ")\n"; }
    ~X() { std::cout << "~X(" << this << ")\n"; }
    X func() { std::cout << "X::func(this " << this << ")\n"; X x(2); return x; }
    int i_;
};

int main()
{
    X x1;
    X x2 = x1.func();
    std::cout << "x1 " << &x1 << ", x2 " << &x2 << '\n';
}

ideone.com上的输出是:

X(0xbfd346e8)
X::func(this 0xbfd346e8)
X(0xbfd346ec, i 2)
x1 0xbfd346e8, x2 0xbfd346ec
~X(0xbfd346ec)
~X(0xbfd346e8)

显示完整的RVO和省略的复制构造,这将是正常生产优化级别(甚至可能更低级别)的大多数编译器的典型。

我建议你使用你曾经使用的任何标志在你的编译器上运行上面的代码,显示的地址应该让你更清楚地了解你观察到的各种操作中涉及哪些对象。你的意见是......

  

仔细观察。这是在&f; func输入&#39;之后调用的。打印出来。这意味着它是从函数内部调用的,即它指的是实例x,而不是x2。

...是有缺陷的逻辑(有更多的态度来启动&#34;我只是等待真正了解复制构造函数的人来回答这个问题。&#34; ),更好的日志记录应该帮助您实现。 (然后希望你向Praetorian道歉。)