假设我有以下代码(它可能过于简单,但我认为它会被采用):
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级的感觉更自然。
现在我发现这个问题在我的代码中一次又一次地发生:我想构建一个复杂的对象,子对象相互引用。根本问题是对象没有被创建和#34;它可能会在构建过程中稍后移动(但不是在构建完所有内容之后)。
他们的任何已知模式都适用于此吗?我想这是一个非常普遍的问题,如果不是,那一定是因为我没有以正确的方式构建我的系统......
有没有办法确保某种RVO?我的意思是,由标准确保,而不是由编译器确保。类似于编译器警告说&#34; BigObject&#34;无法移动到不同的地址&#34;
我还想过删除移动和复制ctor和赋值运算符。但是后来我无法按值返回一个对象,即使实际上没有任何动作......
欢迎任何有用的作品!
答案 0 :(得分:1)
我无法理解为什么在struct BigObject
中需要一个struct对象及其指针。
您可以像这样设计结构:
struct A { ... };
struct BigObject {
A a;
MyOtherClass someMethodUsingA() { /* Here you can use the variable a. */ }
};
如果您仍想按照自己的方式进行编码,可以为struct BigObject
添加copy-construct和assign-construct函数,如下所示:
struct BigObject
{
A a;
B b;
// copy-construct function
BigObject(const BigObject& old)
{
a = old.a;
b = old.b;
b.a_ptr = &a; // pay attetion
}
// assign construct function
BigObject& operator=(const BigObject& old)
{
if (this == &old) // avoid self-assignment
{
return *this;
}
a = old.a;
b = old.b;
b.a_ptr = &a;
return *this;
}
};
答案 1 :(得分:0)
在B函数中添加A引用参数,当BigObject调用函数时,它可以传递给它A. A和B应该是私有的。如有必要,将包装函数添加到BigObject,重定向到A和B的调用,根据需要传递A参数。
不要编写需要RVO才能工作的代码。