存储作为参数传递的引用的内容

Storing the content of a reference passed as a parameter

本文关键字:引用 参数传递 存储      更新时间:2023-10-16

我正在用C++/Qt编程。这些代码片段是否通过复制正确保存了引用的内容?

使用初始化列表:

Foo(const Bar &bar) : bar(bar) { }
Bar bar; //member variable of Foo class

在二传手方法中:

void TestClass::setName(const QString &name) {
    this->name = name;
}
QString name; //member variable of TestClass class

如果是这样,这会复制副本吗?

void TestClass::setName(const QString name) {
    this->name = name;
}
QString name; //member variable of TestClass class

这是否会导致未定义的行为,因为引用的对象可能会提前解构?

Foo(Bar &bar) : bar(bar) { }
Bar &bar; //member variable of Foo class

存储传递的引用的内容是否不好?传递需要存储的参数的更好方法是什么?

复制开销

这两种方法都会将数据从输入字符串复制到类变量中:

QString name; //member variable of TestClass class
void TestClass::setName1(const QString & name) {
    this->name = name;
}
void TestClass::setName2(const QString name) {
    this->name = name;
}

在第二个中,将首先在堆栈上制作QString的副本。您认为按值传递会导致更多的复制开销是正确的。这就是通常不鼓励对包含大量数据的类按值传递的原因。

有关按引用传递与按值传递的更多讨论,请参阅此问题。

但是,在这个特定示例中,开销的差异非常小:QString 使用隐式共享。当您复制 QString 时(例如使用 operator=),它只是创建对相同数据的另一个引用。因此,仅仅复制一个QString——即使是很长的QString——并不比复制一个参考文献更密集。

悬空引用

Foo(Bar &bar) : bar(bar) { }
Bar &bar; //member variable of Foo class

如果在Foo类仍然存在时删除原始bar,则此代码确实会导致问题(这称为"悬空引用")。以这种方式使用引用很像使用指针:作为程序员,您有责任确保所有相关对象都正确管理内存。

如果您担心Qt应用程序中的指针/引用悬而未决,请尝试QPointer:

受保护的指针 QPointer 的行为类似于普通的C++指针 T *,只是在引用的对象被销毁时它会自动设置为 0(与普通的C++指针不同,在这种情况下,指针会变成"悬空指针")。T 必须是 QObject 的子类。

你可以像这样重写上面的代码:

Foo(Bar * bar) : bar(bar) { }
QPointer<Bar> bar; //member variable of Foo class

然后,您可以部分保护免受悬空指针错误的影响:

Bar * myBar = new Bar();
Foo myFoo(myBar);  // myFoo->bar is set to myBar
delete myBar;      // myFoo->bar becomes 0

只要类方法在使用 null 之前检查this->bar null,就可以避免在未初始化的内存上进行操作。(或者,如果你不这样做,你会很快得到一个分段错误,而不是访问已经删除的地址可能更微妙的未定义行为。