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

xto*_*ofl 9 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

 }
Run Code Online (Sandbox Code Playgroud)

私有rvalue超载会吗?

 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?
Run Code Online (Sandbox Code Playgroud)

我有没有看到任何陷阱?

Ori*_*ent 6

如果你有一个存储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!
Run Code Online (Sandbox Code Playgroud)

为了使之成为可能,您应该显式地接受= 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 &&`
};
Run Code Online (Sandbox Code Playgroud)

这种方法允许您禁止将各种右值传递给构造函数。

这也适用于内置标量。例如,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!
Run Code Online (Sandbox Code Playgroud)

对于非转换构造函数(即非一元整数),存在一个问题:您可能必须为= 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;
};
Run Code Online (Sandbox Code Playgroud)

禁止类似以下的混合情况:

B b{};
A a{b, C{}};
Run Code Online (Sandbox Code Playgroud)


hsa*_*ers 2

那不应该编译。一个好的 C++ 编译器(或者几乎所有我见过的 C++ 编译器)将阻止这种情况发生。