C++ 返回*作为参考是否安全?
在中经常使用返回对此对象的引用。它还用作一个基础,允许通过调用setter方法链来初始化对象:C++ 返回*作为参考是否安全?,c++,reference,this,this-pointer,C++,Reference,This,This Pointer,在中经常使用返回对此对象的引用。它还用作一个基础,允许通过调用setter方法链来初始化对象:Params().SetX(1).SetY(1),每个方法都返回对*this的引用 但是返回对*this的引用是否正确。如果我们为临时对象调用返回对此的引用的方法会怎么样: #include <iostream> class Obj { public: Obj(int n): member(n) {} Obj& Me() { return *this; }
Params().SetX(1).SetY(1)
,每个方法都返回对*this的引用
但是返回对*this
的引用是否正确。如果我们为临时对象调用返回对此的引用的方法会怎么样:
#include <iostream>
class Obj
{
public:
Obj(int n): member(n) {}
Obj& Me() { return *this; }
int member;
};
Obj MakeObj(int n)
{
return Obj(n);
}
int main()
{
// Are the following constructions are correct:
std::cout << MakeObj(1).Me().member << std::endl;
std::cout << Obj(2).Me().member << std::endl;
Obj(3).Me() = Obj(4);
return 0;
}
#包括
Obj类
{
公众:
Obj(int n):成员(n){}
Obj&Me(){return*this;}
国际会员;
};
Obj MakeObj(int n)
{
返回Obj(n);
}
int main()
{
//以下结构是否正确:
std::cout是的,这是安全的。临时对象的寿命将持续到语句结束(更准确地说是对创建它的完整表达式的求值)。这由标准保证:
12.2/3:临时对象被销毁,作为计算(词汇上)包含
创建它们的位置
如果绑定到引用,在某些情况下,临时生存期甚至可能会延长。但不要期望出现奇迹。尝试将引用保持在语句之外(例如通过获取地址或分配引用)可能会很快导致UB()
如果在const
对象上使用这种构造,在尝试返回非const
ref时也会遇到一些问题(但这与赋值和setter的示例无关)
//以下构造是否正确:
std::cout是的,返回*这是安全的。简单的情况是,这不是临时的,尽管即使是临时的,也应该可以:
临时对象作为计算完整表达式(1.9)的最后一步被销毁,完整表达式(1.9)包含创建临时对象的点。即使该计算以引发异常(C++03§12.2/3)结束,也是如此
换句话说,在你到达分号之前,一切都应该是好的(理论上)
因此,以下代码应该可以工作:
std::cout << MakeObj(1).Me().member << std::endl;
这两种用法都是安全的。只有当调用代码试图保持引用的时间长于当前语句时,才会出现问题,例如,auto&ref=MakeObj(5.Me();
。是的,您可以创建一个以这种方式指定临时对象的左值(这是我经常纠正使用这些术语的人的原因之一)“临时对象”和“右值”可以互换)我注意到标准库也使用returning*this-:“Return value:*this”。如果标准库使用了不正确的构造,这将很奇怪。:)添加const Obj&Me()const{Return*this;}
因为重载增加了对常量对象的支持。@StellarCortex是的,举例来说!我只是想提醒大家,在一般情况下,应该仔细考虑操作的常量或非常量,尤其是在返回*此
作为参考时。当然,对于赋值运算符和设置器,这不应该是一个问题;-)@M:谢谢,我添加了这个例子。谢谢你指出这种过载。它是怎么命名的?C++版本的哪个版本介绍了这个?我认为它是C++ 11,尽管至少MSVC2013不支持。从我可以读到的,我将它称为函数重载在这个PTR的REF限定符上,不知道官方的名字。
// not allowed:
Obj& ref = MakeObj(1);
std::cout << ref.Me().member << std::endl;
// undefined behaviour:
Obj &ref = MakeObj(1).Me();
std::cout << ref.member << std::endl;
std::cout << MakeObj(1).Me().member << std::endl;
const Obj &MakeMeObj(int n) { return Obj(n).Me(); }
std::cout << MakeMeObj(1).member << std::endl;
Obj &Me() & { return *this; }
Obj &Me() && = delete;