考虑以下代码:
#include <iostream>
struct B {
void bar() {
std::cout << "I feel usedn";
}
};
struct A {
B& b;
A(B& b_) : b(b_) {} // take and keep a reference to the object passed in
void foo() {
b.bar(); // potentially change the state of b
}
};
int main() {
B b;
A a(b);
a.foo();
}
A
的构造函数以对b
的引用为参数,A
通过引用改变b
在其成员函数中的状态。
我的问题:
- 这样做被认为是好的做法吗
- 优点/缺点是什么
- 有什么替代方案
这样做是个好做法吗?
它可能非常危险。你需要确保B的寿命比引用B的A长。有时,使用OP中所示的引用是非常明智的。
缺点是什么?
在某些情况下,确保B的寿命比A长可能非常棘手,如果你引用参数而不是复制它,可能会让客户感到惊讶
有什么替代方案?
std::shared_ptr
(如果为外部所有)。否则,复制或合成可以降低复杂性。
class C { // OK - b obviously outlives a
C() : b(), a(b) {}
B b;
A a;
};
在一个琐碎的程序中,您所做的一切都很好。
我想你会发现,在任何复杂的程序中(例如,那些不是简单语言示例的程序),你最终都需要一个指针(或者更好的是共享ptr),而不是保留对象生命周期的引用。
很有可能,如果你能一直保留一个引用,那么你可能应该使用一个你完全拥有的对象。为什么?当引用超出范围并被销毁时,你会怎么办?
您在这里描述的内容与C++
(或其他语言)的设计而非技术方面有着更紧密的关系,它在UML
中被称为dependency
。这是一种常见的做法,就像任何其他技术一样,在使用之前都应该进行适当的分析,以了解它是否真的适合你的问题的解决方案。您可以在此处找到更多详细信息和用法示例。