use*_*314 4 c++ memory-management unique-ptr c++11 return-by-value
我想知道的是,按值传递Cat实际上与返回std::unique_ptr<Cat>传递它们,内存管理以及在实践中使用它们有何不同.
记忆管理明智,不一样吗?因为返回值对象和包装在unique_ptr中的对象,一旦它们超出范围,它们的析构函数会被触发吗?
那么,你将如何比较两段代码:
Cat catFactory(string catName) {
return Cat(catName);
}
std::unique_ptr<Cat> catFactory(string catName) {
return std::unique_ptr(new Cat(catName));
}
Run Code Online (Sandbox Code Playgroud)
Bri*_*ian 13
按值返回应视为默认值.(*)违反默认惯例,通过返回std::unique_ptr<Cat>,应该要求理由.
返回指针有三个主要原因:
多态性.这是返回的最佳理由,std::unique_ptr<Cat>而不是Cat:您实际上可能正在创建派生自的类型的对象Cat.如果你需要这种多态性,你绝对需要返回某种指针.这就是工厂函数通常返回指针的原因.
Cat不能廉价搬家或根本不能搬家."固有的"不可移动的类型是罕见的; 你应该Cat通过使其便宜地移动来尝试修复.但是当然Cat可以是其他人拥有的类型,你不能添加移动构造函数(或者甚至是复制构造函数).在这种情况下,除了使用之外没有太多可以做的事情unique_ptr(并向所有者投诉).
该函数可能会失败并且无法构造任何有效的函数Cat.在这种情况下,一种可能性是按值返回,但如果Cat不能构造则抛出异常; 另一方面,在C++ 11/C++ 14中,是使函数返回std::unique_ptr<Cat>并在无法Cat构造时返回空指针.但是,在C++ 17中,您应该开始返回std::optional<Cat>而不是std::unique_ptr<Cat>在这种情况下,以避免不必要的堆分配.
(*)这也适用于在被调用的函数需要其自己的值副本时传递对象,例如,将从其一个参数初始化类成员的构造函数.按值接受对象并移动.
默认情况下,按值返回。
此规则的例外情况:
unique_ptr返回 a,而是shared_ptr.我不同意 @Brian 关于他建议的两个例外的回答:
nullptr。未能返回有效值就是异常的原因,即使您想避免它们 - 我建议返回std::expected(使用 C++23)或std::optional(早期的 C++ 版本)。或者如果允许的话,只是在失败时抛出异常。