我有一个“记住”对某个对象的引用的类(例如整数变量)。我不能让它引用一个立即被破坏的值,我正在寻找一种方法来保护我班级的用户不会这样做。
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?
我有没有看到任何陷阱?
答案 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
,也不会延长临时生命周期,直到构造函数完成为止。之后,您将引用无效对象。