传递对C++构造函数的引用

Passing a reference to a C++ constructor

本文关键字:引用 构造函数 C++      更新时间:2023-10-16

我有这个代码:

#include <iostream>
using namespace std;
struct X {
    int a = 1;
};
struct Y {
    X &_x;
    Y(X &x) : _x(x) {}
};
// intentionally typoed version of Y, without the reference in the constructor
struct Z {
    X &_x;
    Z(X x) : _x(x) {}
};
int main() {
    X x;
    Y y(x);
    Z z(x);
    cout << "x:   " << &x << endl;
    cout << "y.x: " << &y._x << endl;
    cout << "z.x: " << &z._x << endl;
}

我一直发现自己忘记了这种格式的类的构造函数中的&

这会输出以下内容:

x:   0xbfa195f8
y.x: 0xbfa195f8
z.x: 0xbfa195fc

为什么yz的行为不同?

为什么在Y的构造函数中用类型为X的实例初始化X &_x成员不是错误?

您的代码接近于具有Undefined Behavior:当Z的构造函数返回时,您正在将引用绑定到超出范围的对象(x),这使它成为一个悬空引用。您以后不会试图取消引用它,这就是UB没有出现的原因。但是,尝试读出z.x的值,而不是取其地址,例如,将是UB。

分配引用不是错误的原因是允许左值引用绑定到左值,并且x是左值。编译器不需要确定是否要访问_x,即使在Z的构造函数返回后也是如此(事实上,恐怕在一般情况下这是不可能的)。

然而,当您尝试将引用绑定到本地对象时,一个好的编译器至少应该发出警告:尝试使用/Wall选项进行编译,您应该得到一个。

关于y.xz.x之间的输出差异:好吧,您打印的是这些变量的地址,而不是它们的值,引用只是它们引用的变量的别名。因此,获取引用的地址与获取其绑定的变量的地址产生相同的结果

z的情况下,引用z.x没有绑定到您在main()中声明的变量x(与y.x不同),而是(实际上)绑定到一个超出范围并包含Z构造函数参数的对象(传递值会创建参数的副本,而z的引用是该副本的别名)。因此,&运算符返回不同的地址。

为什么y和z的行为不同?

因为Y引用了该参数,所以Z没有。Y对原始对象进行操作,Z对副本进行操作。

为什么初始化X&amp_在Y的构造函数中具有x类型实例的x成员?

诊断不是强制性的。在构造函数的作用域之外,引用Z::_x是无效的。因此访问它是无效的(但是,在构造函数内访问_x是可以的)。

调用构造函数时会创建对象的副本,因此z.x的输出不同。该对象的寿命非常有限,它只存在于构造函数中。这是未定义的行为,引用将无效。

为了防止应用程序中出现这种行为,最好将复制构造函数和赋值运算符标记为私有。