Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ RVO(返回值优化)不';我无法解释这个谜_C++ - Fatal编程技术网

C++ RVO(返回值优化)不';我无法解释这个谜

C++ RVO(返回值优化)不';我无法解释这个谜,c++,C++,简单程序: #include <iostream> using namespace::std; class X { public: X() { cout << "Default Constructor called\n"; i = 0; } X(int i) { cout << "Parameterized Constru

简单程序:

#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";    
}
打印“从func返回”后,创建实例x2时不调用构造函数。我实际上期望在实例化x2时调用一个复制构造函数,就像我们执行类似
x2=x1的操作一样

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

在wiki中,RVO定义为:

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

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

1.x2此处不是临时对象。 2.如果真是这样,那么当x从函数返回时,编译器实现RVO会更好。这是临时对象的真实情况(在return语句期间)


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

如果让函数输出更精确的信息,就更容易看到发生了什么。考虑:

#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';
}
这显示了完整的RVO和省略副本结构,这将是大多数编译器在正常生产优化级别(甚至可能更低级别)的典型情况

我建议您在编译器上运行上面的代码,不管您使用了什么标志,显示的地址应该让您更清楚地知道您观察到的各种操作中涉及哪些对象。照现在的情况,你的评论

仔细观察。在打印“func entered”后调用。这意味着它是从函数内部调用的,也就是说,它引用的是实例x,而不是x2


…是有缺陷的逻辑(更倾向于引导“我将等待真正理解复制构造函数的人回答这个问题。”),更好的日志记录应该可以帮助您认识到这一点。(希望您能向Praetorian道歉。)

从func返回的
x2
的构造完成后打印,复制构造函数调用在上面显示的两行输出中可见。我很惊讶你甚至看到了复制构造函数调用,因为NRVO应该有。为什么在函数返回的
行之后会有一个额外的构造函数,当这是你的代码的最后一行时?@TheVigitalTesting那么什么是
参数化构造函数被称为
指的是如果
复制构造函数被称为
指的是
x的构造(这是一个怎样的复制构造)?是什么让你如此确信,你看到的是x2的拷贝结构吗?顺便说一句:当使用g++编译时,永远不会使用合理的编译器(比如gcc)调用复制构造函数(即使在-o0中),并且将-fno-elide构造函数与默认模式进行比较,您会看到通常有两个副本完成,x到retval,retval到x2。两者都可以省略。
#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';
}
X(0xbfd346e8)
X::func(this 0xbfd346e8)
X(0xbfd346ec, i 2)
x1 0xbfd346e8, x2 0xbfd346ec
~X(0xbfd346ec)
~X(0xbfd346e8)