考虑这个课程
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&)
,则常量丢失。
传递指针不会强迫对象真正指向某个东西。
是否可以获得所有三个:
答案 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
应该具有失败模式。智能指针可以自我记录并且对用户而言是直观的。