是否可以将类实例限制为仅用作右值(例如临时值)?
例如,我有一个类Wrapper
,其构造函数采用A const&
并将此引用保存在其成员中。这是危险的,因为Wrapper
实例的生命周期不能超过A
实例的生命周期,但如果Wrapper
为temporary
则没有问题。
答案 0 :(得分:4)
我认为这不安全:
const A &a = YourClass( tmp );
在这种情况下, YourClass
是您要查找的类,只允许临时实例,tmp
是您传递给构造函数的临时值。
有可能(即:安全,定义的行为)具有对临时(即a
)的常量引用,但临时本身(例如YourClass
的实例)已引用{{1在评估该表达式后,它不再有效。
答案 1 :(得分:4)
我认为即使这样做也是一个非常糟糕设计的标志。
但是,您可以将所有构造函数设为私有,并创建一个返回rvalue的友元函数。这应该可以解决问题。
答案 2 :(得分:3)
不完全是您正在寻找的答案,但您是否考虑过弱指针? (例如,boost::weak_ptr
)。在这种情况下,原始A
将保留在shared_ptr
中,而Wrapper
构造函数会接受weak_ptr
。这种方法的巧妙之处在于,在每次使用weak_ptr
之前,您可以尝试lock()
,它将为您提供shared_ptr
- 如果失败,您就知道{{1}已经消失,而A
无法正常运作......但它处理得很干净......
答案 3 :(得分:1)
我不打算在编译时强制执行此操作,因为总会有一些极端情况,这会过度限制,限制了类的有用性,而是包装valgrind或{{}等工具3}}所以我可以找到使用无效引用的地方。
答案 4 :(得分:1)
除非您的班级有公共数据成员,否则这可能会起作用。
基本上,我们的想法不是限制包装器的构造,而是确保实例可以使用(就像你说的那样)只要它们是临时值。人们可以通过重载所有方法并删除(或使它们成为私有)那些引用const&的方法来实现这一点。
这是一个简单的例子:
class Wrapper
{
public:
Wrapper() = default;
Wrapper(const std::string& name) : name(name) {}
void process() && { std::cout << "Greetings from " << name << std::endl; }
// Only temporary instances of this class are allowed!
void process() const & = delete;
private:
std::string name;
};
还有一些用例:
Wrapper("John").process(); // intended use case
Wrapper j; // create whatever you want
j.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
std::move(j).process(); // this is still possible
const Wrapper& t = Wrapper(); // bind the temporary to a const reference - not a problem because ...
t.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
明显的缺点是:
标准中也做了类似的事情。 std :: reference_wrapper do not accept temporaries的make例程。
请注意,他们考虑了另一个微妙之处:重载使用const T&amp;&amp;而不是T&amp;&amp ;.这在我们的案例中也很重要。例如,如果您的包装器被故意设计为不可复制,并且您使用make例程,例如
const Wrapper make_wrapper();
而不是
Wrapper make_wrapper();
在这种情况下,您可能想要替换
void process() &&;
通过
void process() const &&;
答案 5 :(得分:0)
是的,你可以。
你可以使构造函数和常规的copy-constructor / assign私有,但是将r值移动语义(C ++ 0x)公开。
您可以使用静态或朋友构造函数来创建临时。
在2003 C ++中,您还可以使用它来绑定到const引用。
当然,你会遇到这样的问题:你的const引用可能会在语句后失效。