为什么在此代码片段中两次调用了复制构造函数?

时间:2019-02-28 15:37:44

标签: c++ c++14 copy-constructor

我正在研究一些事情,以了解复制构造函数的工作方式。但是我无法理解为什么在创建x2时两次调用了复制构造函数。我以为将createX()的返回值复制到x2时会调用一次。
我还查看了一些有关SO的相关问题,但据我所知,我找不到与我在此处询问的相同的简单情况。

顺便说一句,我正在使用-fno-elide-constructors进行编译,以了解未进行优化的情况。

#include <iostream>

struct X {
    int i{2};

    X() {
        std::cout << "default constructor called" << std::endl;
    }

    X(const X& other) {
        std::cout << "copy constructor called" << std::endl;
    }
};

X createX() {
    X x;
    std::cout << "created x on the stack" << std::endl;
    return x;
}

int main() {
    X x1;
    std::cout << "created x1" << std::endl;
    std::cout << "x1: " << x1.i << std::endl << std::endl;    

    X x2 = createX();
    std::cout << "created x2" << std::endl;
    std::cout << "x2: " << x2.i << std::endl;    

    return 0;
}

这是输出:

default constructor called
created x1
x1: 2

default constructor called
created x on the stack
copy constructor called
copy constructor called
created x2
x2: 2

有人可以帮我我在这里遗失或忽略的东西吗?

2 个答案:

答案 0 :(得分:19)

您在这里必须记住的是,函数的返回值是一个不同的对象。当你做

return x;

您复制使用x初始化返回值对象。这是您看到的第一个副本构造函数调用。然后

X x2 = createX();

使用返回的对象复制初始化x2,这是您看到的第二个副本。


要注意的一件事是

return x;

将尝试将x移入返回对象。如果您创建了一个move构造函数,您将看到此调用。这样做的原因是,由于局部对象在函数末尾超出范围,因此编译器将对象视为右值,并且只有在找不到有效的重载时,它才退回到以左值返回。 / p>

答案 1 :(得分:12)

第一个副本是createX的返回

X createX() {
    X x;
    std::cout << "created x on the stack" << std::endl;
    return x; // First copy
}

第二个是从createX的临时返回中创建x2。

X x2 = createX(); // Second copy

请注意,在C ++ 17中,第二个副本被强制删除。

相关问题