防止临时对象的传递引用
prevent pass-by-ref of temporary object
我有一个类,它"记住"对某个对象的引用(例如整数变量)。 我不能让它引用立即销毁的值,我正在寻找一种方法来保护我的类的用户不会意外这样做。
右值引用重载是防止传入临时的好方法吗?
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?
有什么陷阱我没有看到吗?
如果您必须在类A
中存储对某个类型 B
实例的const
引用,那么您肯定希望确保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;
所有构造函数重载,这些重载可以接受右值(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 &&`
};
此方法允许您禁止向构造函数传递各种右值。
这也适用于内置标量。例如,double const f() { return 0.01; }
,尽管它会导致如下警告:
警告:返回类型的"const"类型限定符不起作用 [-Wignore 限定符]
如果您只= 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{}};
代码无效的事实,只回答有关私有重载的问题......
在 C++11 中,我更喜欢删除的功能而不是私有功能。更明确的是,你真的不能称呼它(即使你是班级的成员或朋友。
注意:如果删除的构造函数HasRef(int&&)=delete
则不会在此处选择:
int i;
HasRef hr(std::forward<const int>(i));
对于类型 const int&&
的参数,将使用 HasRef(const int&)
构造函数,而不是HasRef(int&&)
构造函数。在这种情况下,这是可以的,因为i
确实是一个左值,但一般来说可能并非如此,所以这可能是常量右值引用有用的非常罕见的情况之一:
HasRef(const int&&) = delete;
这不应该编译。一个好的C++编译器(或者我见过的几乎任何C++编译器)将阻止这种情况发生。
我猜你是在MSVS中编译的。在这种情况下,请关闭语言扩展,您应该会收到错误。
否则,即使标记引用const
也不会延长临时的生存期,直到构造函数完成。之后,您将引用无效对象。
- 为什么当我们有常量引用时创建临时对象?
- 返回对临时对象的引用
- 通过引用传递临时对象
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 对临时对象的Const引用不会延长其生存期
- 为什么引用类型在使用临时对象访问时是左值
- 取消引用临时对象上的运算符
- 常量引用函数参数:是否可以禁止临时对象?
- 为什么临时对象可以绑定到常量引用?
- 为什么常量引用不能延长通过函数传递的临时对象的生存期?
- 使用常量引用延长临时对象的寿命
- 从函数返回引用是否会导致在使用'auto'时创建新的临时对象?
- 关于将临时对象传递给常量引用
- 将临时对象绑定到常量引用
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)
- 返回对本地临时对象 C++ 的引用
- 模板类型推导警告返回对本地临时对象的引用
- 为什么不对临时对象进行非常量引用
- 为什么我们可以非常量引用临时对象并延长其生命周期
- C++悬空的常量引用临时对象