例子:
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);
}
例子:
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)...));
在这行代码中,执行显式动态分配。最佳实践规定,无论何时执行显式动态分配,都应立即将结果分配给命名的智能指针。有关更多详细信息,请参阅Boostshared_ptr
最佳实践文档或 Herb Sutter 的 GotW 文章“异常安全函数调用”。
将表达式作为较大表达式的子表达式并不总是很危险,但这是一个很容易忘记的规则,因此最好始终遵循最佳实践指南并将新的动态分配对象分配给命名智能指针new
.
也就是说,创建命名对象然后返回它的模式至少有一个优点:在快速单步执行代码时,可以更容易地在调试器中“观察”对象。
一个可能的缺点是编译器可能更难以使用命名对象执行返回值优化 (RVO)。命名返回值优化 (NRVO) 并不总是像带有未命名临时的 RVO 那样简单。我敢猜测现代编译器不会有任何问题,但我不是 C++ 编译器优化方面的专家。
从历史上看,第一个版本
Foo make_foo(int a1, int a2)
{
Foo f(a1,a2);
return f;
}
在某些编译器(如旧版 MSVC)中触发 NRVO 优化的机会更大。
版本 2应该同样适用于实现RVO的编译器,但从历史上看它并不可靠。
就个人而言,每当我编写类模板时,我也会编写相应的make_
函数模板,以允许创建类模板类型的对象,而无需显式指定模板参数。当然,这通常仅在使用具有 C++0xauto
语义的编译器或将临时参数作为函数参数传递时,但在我看来,这两种情况都很常见,值得付出努力。
也就是说,我从未编写过这样的代码来创建非模板类型。