当返回一个对象时,为什么要将创建+初始化和返回作为两个单独的语句,而不是一个
When returning an object, why put the creation+initialization and the return as two seperate statements instead of one?
示例:
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的编译器同样有效,但从历史上看,它并不那么可靠。
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 如何在C++中从两个单独的for循环中添加两个数组
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- CoInitialize()在单独的线程上崩溃而不返回
- 我可以制作一个对象方法,如果单独调用,它将自行修改,但如果在复制初始化期间调用,则会返回一个新对象?
- 将单独的头文件和类定义文件链接到主函数文件 - G++ 返回重载"undefined reference to"构造函数
- C++:两个单独的函数在嵌套时返回不同的结果?
- 单独线程中的 GetDC 函数需要很长时间才能返回
- 如何在单独的线程中调用方法并使用返回状态
- 使用单独编译时返回一个typedef类型
- 从c++中单独的函数返回值
- c++数据成员在单独的成员函数中定义后返回垃圾
- 基于单独的模板化成员改变类的模板化成员函数的返回类型
- 当返回一个对象时,为什么要将创建+初始化和返回作为两个单独的语句,而不是一个
- 如果从类(在单独的文件中)调用SDL UpdateWindowSurface(),则返回-1