强制非null,同时保留constness

时间:2015-12-23 13:50:01

标签: c++ pointers reference const

考虑这个课程

class Foo
{
public:
    Foo()
       : r_obj(&nullobj)
    {}

    void setDataRef(const T& obj)
    {
        r_obj = &obj;
    }

private:
    static T nullobj;
    const T* r_obj;
};

这迫使r_obj指向某个东西,我知道该类无法修改它指向的任何逻辑状态。但是,现在将临时对象传递给setDataRef是非常合理的,这是非常糟糕的。

如果改为使用setDataRef(T&),则常量丢失。

传递指针不会强迫对象真正指向某个东西。

是否可以获得所有三个:

  • 常量性
  • 非空
  • 禁止临时

2 个答案:

答案 0 :(得分:6)

在旧的C ++中我认为这是不可能的,但是使用C ++ 11我们可以做到:

class Foo
{
public:
    Foo()
       : r_obj(&nullobj)
    {}

    void setDataRef(const T& obj)
    {
        r_obj = &obj;
    }
    void setDataRef(T&& obj) = delete;   // Crucial extra line

private:
    static T nullobj;
    const T* r_obj;
};

如果有人试图将临时值传递给setDataRef,则重载解析会更喜欢T&&版本,但由于它被删除,因此调用格式不正确。如果某人传递左值,那将绑定到const引用。

答案 1 :(得分:4)

Martin的建议非常好,并且确实阻止了调用者将rvalue传递给函数。但是,这仍然不能保证传递的对象的生命周期超出Foo实例的生命周期。

如果对象存储指向传递的对象的指针,那么如果将指针传递给setter则最直观。传递指针也会阻止使用rvalue(因为不允许使用rvalue的地址)。

就像你必须记录传递对象必须存在的接口一样,只要存在Foo实例,你也可以记录传递的指针不能为空。另外,你可以断言它。您可以类似地删除nullptr_t的重载,以防止将文字传递给setter,但不会阻止传递T*类型的空指针。在我看来,参考设定器的优势并不大。

当然,原始指针和引用都不会告诉调用者关于所有权的任何内容,因此必须记录在任何一种情况下。相反,我建议存储和传递智能指针。 unique_ptr如果Foo应该拥有所有权(显然不是),shared_ptr Foo weak_ptr如果对象超出其他地方的范围,或者{{1}当引用的对象不再存在时,Foo应该具有失败模式。智能指针可以自我记录并且对用户而言是直观的。