【发布时间】:2014-12-19 18:41:00
【问题描述】:
假设我有:
class Metadata {
// stores expensive-to-copy data, provides complex interface to access/modify
}
class SomeObject
public:
Metadata& GetMetadata() { return mMetadata; }
private:
Metadata mMetadata;
}
boost::shared_ptr<SomeObject> obj = ...;
obj->GetMetadata().SetTitle("foo");
obj->GetMetadata().GetTitle();
普遍的共识似乎是通过引用返回,尤其是非常量,除了少数特定情况外,在所有情况下都非常糟糕。但是,在这种情况下,它似乎是最好的(也是唯一的?)选择:
- 我不想退回副本,因为我想修改原件(即使是 r/o,复制也很昂贵)。
- 我不想返回 Metadata* 或类似的东西,因为我不想鼓励存储或传递指针。
- 我不想通过对元数据的无关包装调用来污染 SomeObject 的接口。
它引入了一个模糊的要求,即 SomeObject 能够通过引用传回 Metadata,这意味着必须有一个 Metadata 对象,其生命周期与 SomeObject 的生命周期相同(或长于)——然而,这就是它们之间的确切语义关系对象,并且要求肯定比上述任何选项都好。
我突然想到我可以引入某种不可复制的指针类型并返回它,但这闻起来很有趣/似乎有点矫枉过正。我可以让 SomeObject 拥有一个 boost::shared_ptr,但这确实不适合我想到的语义(基本上:如果您现在正在修改,请修改原始 - 如果您稍后阅读/存储,制作副本并自行跟踪)。
这里有更好的模式吗?我会以某种我看不到的方式在自己的脚上开枪吗?
【问题讨论】:
-
谁告诉你这很糟糕?返回对类数据成员的引用是一种普遍且有用的编程技术。
-
我认为返回非常量引用没有问题。虽然将成员变量公开可能更简单。
-
鉴于
Metadata已经封装了原始数据,将mMetadata设为SomeObject的公共成员(最好使用更好的名称)并直接使用它也可能完全没问题通过GetMetadata()(在这种情况下似乎没有完成任何事情)。 -
@KerrekSB Scott Meyers 做了(有效的 C++ 项目 28)。虽然他确实说有像矢量这样的例外。
-
对
Metadata的包装器调用可能是不必要的,但它们不应该是“不相关的”,否则Metadata不属于SomeObject。
标签: c++ design-patterns reference ownership