当返回一个对象时,为什么要将创建+初始化和返回作为两个单独的语句,而不是一个

When returning an object, why put the creation+initialization and the return as two seperate statements instead of one?

本文关键字:返回 单独 两个 一个 语句 为什么 一个对象 创建 初始化      更新时间:2023-10-16

示例:

Foo make_foo(int a1, int a2){
  Foo f(a1,a2);
  return f;
}

看过几次这样的函数后,这只是编码风格/偏好的问题,还是它的内容超出了我们的想象?具体来说,这个答案让我思考make_unique实现和它是异常安全的声明——这与创建和返回的拆分有关吗?还是我对此读得太多了?为什么不简单地写

Foo make_foo(int a1, int a2){
  return Foo(a1,a2);
}

将创建和返回结合起来是完全可以的,教科书通常在单独的行中进行,以在一定程度上澄清代码。

请注意,您所指的答案实际上有所不同:

std::unique_ptr<T> ret (new T(std::forward<Args>(args)...));

在这行代码中,执行显式动态分配。最佳实践规定,无论何时执行显式动态分配,都应立即将结果分配给命名的智能指针。有关更多详细信息,请参阅Boost shared_ptr最佳实践文档或Herb Sutter的GotW文章"异常安全函数调用"

new表达式作为较大表达式的子表达式并不总是危险的,但这是一条很容易忘记的规则,因此最好始终遵循最佳实践指南,并将新的动态分配对象分配给命名的智能指针。


也就是说,创建一个命名对象然后返回它的模式至少有一个优点:当快速遍历代码时,在调试器中"观察"对象会更容易。

一个可能的缺点是,编译器可能更难对命名对象执行返回值优化(RVO)。命名返回值优化(NRVO)并不总是像具有未命名临时的RVO那样简单。我大胆地猜测,无论哪种方式,现代编译器都不会有问题,但我不是C++编译器优化方面的专家。

这完全取决于您的需求,您可以将它们放入一个语句中。这样做是为了提高代码的可读性。

的大多数书籍和其他技术资源中,前几章中有单独的创建、实例化和返回语句,但当您继续阅读时,它们会合并为一个语句。

就我个人而言,每当我编写类模板时,我也会编写相应的make_函数模板,以便在不显式指定模板参数的情况下创建类模板类型的对象。当然,这通常只有在使用具有C++0x的auto语义的编译器时,或者在将临时参数作为函数参数传递时才会发生,但在我看来,这两种情况都很常见,足以保证所做的努力。

也就是说,我从来没有写过这样的代码来创建非模板类型。

历史上,的第一个版本

Foo make_foo(int a1, int a2)
{
    Foo f(a1,a2);
    return f; 
} 

在某些编译器(如较旧的MSVC)中有更好的机会触发NRVO优化。

版本2应该对于实现RVO的编译器同样有效,但从历史上看,它并不那么可靠。