防止临时对象的pass-by-ref

时间:2012-06-20 20:38:09

标签: c++ pass-by-reference rvalue-reference pass-by-rvalue-reference

我有一个“记住”对某个对象的引用的类(例如整数变量)。我不能让它引用一个立即被破坏的值,我正在寻找一种方法来保护我班级的用户不会这样做。

rvalue-reference重载是否是防止临时传入的好方法?

struct HasRef {
    int& a;
    HasRef(int& a):a(a){}
    void foo(){ a=1; }
};


int main(){
    int x=5;
    HasRef r1(x);
    r1.foo();  // works like intended.

    HasRef r2(x+4);
    r2.foo(); // dereferences the temporary created by x+4

 }

私有右值超载会发生吗?

 struct HasRef {
   int& a;
   HasRef( int& a ):a(a){}
   void foo(){ a=1; }
 private: 
   HasRef( int&& a );
 };

 ... HasRef r2(x+1); // doesn't compile => problem solved?

我有没有看到任何陷阱?

4 个答案:

答案 0 :(得分:4)

如果您必须将const类似B类型的实例存储到您的班级A,那么您肯定希望确保A的生命周期实例将超过B实例的生命周期:

B b{};
A a1{b}; // allowed
A a2{B{}}; // should be denied
B const f() { return B{}; } // const result type may make sense for user-defined types
A a3{f()}; // should also be denied!

为了使您可以明确地= delete;所有构造函数重载,它可以接受rvalues(const &&&&)。为此,您只需要= delete; const &&版本的构造函数。

struct B {};

struct A
{
    B const & b;
    A(B const & bb) : b(bb) { ; } // accepts only `B const &` and `B &`
    A(B const &&) = delete; // prohibits both `B &&` and `B const &&`
};

这种方法允许您禁止向构造函数传递各种rvalues。

这也适用于内置标量。例如,double const f() { return 0.01; },但会引发类似警告:

  

警告:返回类型的'const'类型限定符无效[-Wignored-qualifiers]

只有= delete;&&版本的构造函数,它仍然有效:

struct A
{
    double const & eps;
    A(double const & e) : eps(e) {} // binds to `double const &`, `double &` AND ! `double const &&`
    A(double &&) = delete; // prohibit to binding only to `double &&`, but not to `double const &&`
};

double const get_eps() { return 0.01; }

A a{0.01}; // hard error
A a{get_eps()}; // no hard error, but it is wrong!

对于非转换构造函数(即非一元),存在一个问题:您可能必须为所有组合可能的构造函数版本提供= delete; - d版本,如下所示:

struct A
{
    A(B const &, C const &) {}
    A(B const &&, C const &&) = delete;
    // and also!
    A(B const &, C const &&) = delete;
    A(B const &&, C const &) = delete;
};

禁止混合案例如:

B b{};
A a{b, C{}};

答案 1 :(得分:3)

忽略代码无效的事实,只是回答有关私有超载的问题......

在C ++ 11中,我更喜欢将删除的函数用于私有函数。更明确的是,真的无法调用它(即使您是该类的成员或朋友也不会。)

N.B。如果删除的构造函数为HasRef(int&&)=delete,则不会在此处选择:

int i;
HasRef hr(std::forward<const int>(i));

使用const int&&类型的参数,将使用HasRef(const int&)构造函数,而不是HasRef(int&&)构造函数。在这种情况下,它会没问题,因为i实际上是一个左值,但通常情况可能并非如此,所以这可能是 const 右值的非常罕见的时间之一参考是有用的:

HasRef(const int&&) = delete;

答案 2 :(得分:2)

那不应该编译。一个好的C ++编译器(或者几乎所有我见过的C ++编译器)都会阻止它发生。

答案 3 :(得分:0)

我猜你正在编译MSVS。在这种情况下,请关闭语言扩展,您应该收到错误。

否则,即使标记引用const,也不会延长临时生命周期,直到构造函数完成为止。之后,您将引用无效对象。

相关问题