【问题标题】:Hiding pointers with references用引用隐藏指针
【发布时间】:2013-04-18 17:01:53
【问题描述】:

用使用引用的setter隐藏指针成员是好事吗?

class Foo
{
    Bar* m_ptr;
public :
    void setBar(Bar& bar){m_ptr = &bar;}
};

或者最好在 setter 中公开被引用对象的真实类型(以及为什么)?

void setBar(Bar* bar){m_ptr = bar;}

事实上,我使用的是非“引用友好”的 stl 竞争者,因此我将指针向量作为类成员,但我更喜欢处理接受引用的方法。这样做是坏事吗?

编辑:

存储的成员是指针,这个例子更适合我的问题:

class Foo
{
   std::vector<FooObserver *> m_observers; 
public :

你喜欢这个吗:

void addObserver(FooObserver* obs);

或者这个:

void addObserver(FooObserver& obs);

?

在这两种情况下,指针都不应该为 NULL,我认为这是调用者对象的责任。

【问题讨论】:

    标签: c++ pointers reference


    【解决方案1】:

    对我来说,它归结为类型的语义。如果指针掩盖了一个永远不会成为NULL 的成员,那么绝对在输入和输出位置都使用引用。如果值可以合法地为NULL,那么使用指针是最好的方法

    【讨论】:

    • 这是一个简单而好的规则,但我忘记提到(在编辑之前)存储的成员永远不应该为 NULL。我还需要存储的成员不只是引用。
    【解决方案2】:

    这取决于你想要达到什么,两者都是完全合理的。

    唯一的区别*是void setBar(Bar* bar) 将接受空指针,而void setBar(Bar&amp; bar) 显然不会。

    您可以根据是否允许空指针来选择要使用哪一个。

    (*) 假设Bar 的作者没有提供自定义operator&amp;(无论如何这是一个糟糕的想法)。


    编辑:由于您不想允许存储空指针,因此最好使用引用。您说“指针永远不应该为 NULL,我认为这是调用者对象的责任”,但是通过引用,您有机会在编译时强制执行这一点,并避免完全依赖调用者的善意,这是更好的设计。

    【讨论】:

    • 等等。如果setBar 接受引用,而我做Bar *b = NULL; setBar(*b),在setBar 中,你接受&amp;bar 并将其存储在向量中,没有问题。您仍然收到 NULL。引用不会阻止您获得 NULL。
    • 一般来说,他们使用引用来表明您计划不接受 NULL 的意图。除此之外,该语言不会阻止您获得它。
    • @Shahbaz:取消引用空指针是未定义的行为,因此不正确的 C++。一些(大多数/所有)编译器可能会出于效率考虑而选择只允许您编写的内容(否则他们必须在运行时检查每个取消引用的正确性,让您的程序爬行的方式)但这并没有使其合法。
    • @syam,我知道这是未定义的行为。但是编译器没有办法检查它。所以我指出句子 void setBar(Bar* bar) 将接受空指针,而 void setBar(Bar& bar) 显然不会。 并不完全正确,因为参考版本可能仍然会得到一个 NULL 引用。更好的措辞是而 void setBar(Bar& bar) 不打算接受它们。
    • @syam,我明白了。我不知道&amp;(*(Bar *)0) 会是未定义的行为。我以为这会合法地减少到(Bar *)0
    【解决方案3】:

    是的。由于它混淆了您对这两个对象的终生控制,请考虑这一点

    void AdjustFoo(Foo& f)
    {
    
         Bar B;
         f.setBar(B);
         //Crap f now contains a bad pointer to B after this function exists 
    }
    

    如果 foo 需要拥有一个 B,它应该拥有一个 shared_ptr 或 B 的副本。

    【讨论】:

    • 我认为一般属性应该是value types
    • @Laurent 我同意,但指针暗示您需要关注生命周期问题。参考使它变得太容易了。
    • @DyP 是的,这是一个坏主意。使用refrece但不参与所有权的函数没有问题。
    • @rerun 好的,所以您建议公开存储值的类型会“警告”用户小心他在做什么,不是吗?
    • 我知道这是个坏主意,我只是感到困惑,因为 OP 有三个问题,其中最后一个问题被公式化为第一个问题的反转。
    【解决方案4】:

    这是一个约定俗成的问题,但我更喜欢包含以下内容的:

    • 如果被调用的方法保留了传递对象的指针,请使用指针参数并在 API 文档中明确说明生命周期要求
    • 如果被调用的方法只是在方法执行期间窥视(并且可能是戳)到传递的对象,请使用引用。
    • 接受引用表示:我只接受有效对象。
    • 接受指针表示:除非另有明确说明,否则我也接受空指针。

    顺便说一句,我不喜欢到处放置共享指针。终生失去控制,所有权变得模糊。当然,共享指针仍然有非常有效的用途,但不要仅仅因为您不想考虑生命周期和所有权而使用它们。

    【讨论】:

      猜你喜欢
      • 2011-08-24
      • 2012-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-05
      • 1970-01-01
      • 2013-12-25
      相关资源
      最近更新 更多