通过引用返回的成员变量EVER可以接受吗?

时间:2014-10-23 23:31:11

标签: c++ design-patterns reference ownership

假设我有:

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();

普遍的共识似乎是,通过引用返回,特别是非常量,在除了少数特定情况之外的所有情况都非常糟糕。但是,在这种情况下,它似乎是最好的(也是唯一的?)选项:

  1. 我不想退回副本,因为我想修改原始(即使它是r / o,复制也很昂贵)。
  2. 我不想返回Metadata *或类似的东西,因为我不想鼓励存储或传递指针。
  3. 我不想通过对Metadata进行无关的包装调用来污染SomeObject的接口。
  4. 它引入了一个模糊的要求,即SomeObject能够通过引用传回元数据,这意味着必须有一个元数据对象,其生命周期与SomeObject的生命周期相同(或者更长) - 但是,这是它们之间的确切语义关系对象,并要求肯定比上述任何选项更好。

    在我看来,我可以引入某种不可复制的指针类型并返回它,但那闻起来很有趣/看起来有点矫枉过正。我可以让SomeObject拥有一个boost :: shared_ptr,但这真的不是我想到的语义的一个很好的匹配(基本上:如果你现在修改,修改原始 - 如果你以后读/存储,制作副本并自己跟踪。)

    这里有更好的模式吗?我会以某种方式在脚下射击自己吗?

2 个答案:

答案 0 :(得分:6)

返回一个比函数调用更长的东西的引用完全没问题。当您将lvalue引用返回给类数据成员时,只需确保该类实例本身就是左值:

struct Foo
{
    X data;

    X & the_data() &   { return data; }
//                ^^^

如果你的实例是左值,你也可以将数据作为右值返回:

    X && the_data() && { return std::move(data); }
};

答案 1 :(得分:0)

当然,只要您没有返回对本地(自动)存储的引用,就可以返回引用。在大多数情况下,您应该返回const引用。

这允许C ++编译器(通过设计积极优化语言编译器)优化掉很多东西,并且还允许编写“流畅”的语法。

obj.foo().bar().baz();