为什么在此代码代码段中将复制构造函数两次称为两次

Why is the copy constructor called twice in this code snippet?

本文关键字:两次 代码 构造函数 段中 复制 为什么      更新时间:2023-10-16

我正在玩一些事情,以了解复制构造仪的工作方式。但是我无法理解为什么要为x2创建两次复制构造函数。我会以为当createX()的返回值复制到x2中时会被调用一次。
我还查看了一些相关的问题,但是据我所知,我找不到与我在这里问的简单场景。

顺便说一句,我正在使用-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

有人可以帮助我在这里缺少或忽略什么?

您必须记住的是,函数的返回值是一个独特的对象。当你做

return x;

x复制返回值对象。这是您看到的第一个复制构造函数。然后

X x2 = createX();

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


要注意的一件事是

return x;

如果可以的话,将尝试将x移至返回对象。如果您制作了一个移动构造函数,您会看到这一点。这样做的原因是,由于本地对象在函数末尾不在范围内,因此编译器将对象视为rvalue,并且只有当找不到有效的过载时,才能将其归还为lvalue。/p>

第一个复制是rextrex

的回报
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中,第二份副本被迫被省略。