返回 \*this 作为参考是否安全?

新手上路,请多包涵

返回对该对象的引用通常用于 赋值运算符重载。它还用作 命名参数习惯用法 的基础,它允许通过对 setter 方法的调用链来初始化对象: Params().SetX(1).SetY(1) 每个都返回对 *this 的引用。

但是返回对 *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;
}

原文由 anton_rh 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 469
2 个回答

是的,退回 *this 是安全的。最简单的情况是,这不是暂时的,但即使是,这也应该是可能的:

临时对象被销毁作为评估完整表达式(1.9)的最后一步,该完整表达式(在词法上)包含它们被创建的点。即使评估以抛出异常结束(C++03 §12.2/3)也是如此。

换句话说,在你到达分号之前,一切都应该没问题(理论上)。

所以下面的代码应该可以工作:

 std::cout << MakeObj(1).Me().member << std::endl;

虽然这不应该工作:

 const Obj &MakeMeObj(int n) { return Obj(n).Me(); }
std::cout << MakeMeObj(1).member << std::endl;

这是合乎逻辑的,因为您正在返回对临时的引用。大多数编译器都会对此发出警告/错误,但如果您的代码变得复杂,则需要注意这一点。

就个人而言,我会阻止在临时对象上调用这些方法来强制 API 用户考虑对象的生命周期。这可以通过重载您的方法来完成:(如果您的编译器已经支持它)

 Obj &Me() & { return *this; }
Obj &Me() && = delete;

原文由 JVApen 发布,翻译遵循 CC BY-SA 3.0 许可协议

> // Are the following constructions are correct:
> std::cout << MakeObj(1).Me().member << std::endl;
> std::cout << Obj(2).Me().member << std::endl;
>
> ```

是的,因为在每一行中,所有临时对象的生命周期都被延长以考虑 **完整的表达式**。

正如 [cppreference.com](http://en.cppreference.com/w/cpp/language/lifetime) 所说:

> (...) 作为评估完整表达式的最后一步,所有临时对象都被销毁,该完整表达式(在词法上)包含创建它们的点 (...)。

如果您尝试拆分完整的表达式,那么您(希望)会收到编译器错误或警告:

// 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;

”`

原文由 Christian Hackl 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题