【发布时间】:2014-03-14 14:10:21
【问题描述】:
假设我有以下代码(它可能过于简单,但我认为这就足够了):
struct BigObject {
A a;
B b;
};
struct A { ... };
struct B {
A const* a_ptr;
MyOtherClass someMethodUsingA() { ... }
}
class BigObjectBuilder {
BigObject build() {
BigObject o;
o.a = buildA();
o.b.a_ptr = &(o.a);
return o;
}
}
问题在于 &(o.a) 可能会指向稍后的任何内容,因为 o 的地址在返回时可能已更改(调用移动或复制构造函数)。现在我发现大多数时候 &(o.a) 是相同的,所以调用 *(o.b.a_ptr) 不会导致段错误。 (我认为这是由于 RVO,因为那时 o 没有移动)。无论如何,只要我不确定 o 的地址没有改变,这段代码就不正确。
一个明显的解决方案是要求动态分配我的 BigObject:
auto o_ptr = make_unique<BigObject>();
这个解决方案还不错(没有泄漏,并且解决了前面的问题。),但是我仍然觉得它不够优雅:我不需要动态分配,我只需要为我的 BigObject 提供一个固定地址。这将是我认为的 Java 做事方式。 另一种解决方案是在 B 中使用副本,但是 o.a 中的所有更改都不会影响 o.b.a,我不希望这样。
第三种解决方案是在 B 中没有 A 的副本、ptr 或引用,并在方法 B::someMethodUsingA() 的参数中传递 A。但同样,在调用此函数时查找要传递的参数可能很乏味。有时,B 类有一个指向 A 类的指针感觉更自然。
现在我发现这个问题在我的代码中一次又一次地发生:我想构建一个复杂的对象,子对象相互引用。根本问题是对象不是“就地”创建的,它可能会在构建过程中稍后移动(但不是在构建完所有内容之后)。
他们是否有任何已知的模式可以适用于此?我想这是一个很常见的问题,如果不是,那一定是因为我没有以正确的方式构建我的系统......
有没有办法确保某种 RVO ?我的意思是,由标准确保,而不是由编译器确保。类似于编译器警告说“BigObject”不能移动到不同的地址”
我还想过删除移动和复制 ctor 和赋值运算符。但是我无法按值返回对象,即使实际上没有任何移动......
欢迎分享任何对你有用的东西!
【问题讨论】: