是否可以将类实例限制为仅用作临时实例?

时间:2011-01-31 12:10:10

标签: c++ c++11

是否可以将类实例限制为仅用作右值(例如临时值)?

例如,我有一个类Wrapper,其构造函数采用A const&并将此引用保存在其成员中。这是危险的,因为Wrapper实例的生命周期不能超过A实例的生命周期,但如果Wrappertemporary则没有问题。

6 个答案:

答案 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引用可能会在语句后失效。