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

c_s*_*ent 14 c++ copy-constructor c++14

我正在玩一些东西来理解复制构造函数的工作原理.但我无法理解为什么复制构造函数被调用两次才能创建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;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

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
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我,我想要或忽略这里?

Nat*_*ica 19

你必须记住的是函数的返回值是一个独特的对象.当你这样做

return x;
Run Code Online (Sandbox Code Playgroud)

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

X x2 = createX();
Run Code Online (Sandbox Code Playgroud)

使用返回的对象复制initialize x2,这是您看到的第二个副本.


有一点需要注意的是

return x;
Run Code Online (Sandbox Code Playgroud)

x如果可以,将尝试进入返回对象.如果你做了一个移动构造函数,你会看到这个叫做.这样做的原因是,由于本地对象在函数末尾超出范围,编译器会将对象视为右值,并且只有在找不到有效的重载时才会将其作为左值返回.


Jar*_*d42 12

第一个副本是createX的回报

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

第二个是通过createX从临时返回创建x2.

X x2 = createX(); // Second copy
Run Code Online (Sandbox Code Playgroud)

请注意,在C++ 17中,强制要求省略第二个副本.