函数是不是应该返回一个“新”对象
Posted
技术标签:
【中文标题】函数是不是应该返回一个“新”对象【英文标题】:Should a function return a "new" object函数是否应该返回一个“新”对象 【发布时间】:2017-09-10 23:44:08 【问题描述】:函数是否应该返回指向在堆上分配的内存的指针?
也就是说,以下哪种方法更“正确”?
// Method #1
Object* getObject1()
return new Object();
// Method #2
std::shared_ptr<Object> getObject2()
return std::make_shared<Object>();
int main()
// Usage of method #1
Object* o1 = getObject1();
o1->doSomething();
delete o1; // object has to be deleted by user
// Usage of method #2
std::shared_ptr<Object>& o2 getObject2(); // has to be kept in shared_ptr
o2.get()->doSomething();
// object is deleted when o2 destructs
我想第一种方法可能更快,但第二种方法不需要用户删除对象。
【问题讨论】:
为什么第一种方法应该“更快”?您是否试图在紧密循环中每秒调用一百万次? 第一个解决方案在现代 c++ 中没有一席之地。至少,它应该创建并返回一个std::unique_ptr<Object>
。
还有方法3,返回std::unique_ptr<Object>
。如果不确定,请这样做。没有开销,您始终可以将唯一指针转换为共享指针(在进程中使用它)。此外,您不能忘记删除unique_ptr
。
Herb Sutter - 对象工厂:herbsutter.com/2013/05/30/gotw-90-solution-factories
@ChristianHackl,为什么不呢?
【参考方案1】:
这两种选择都不是很好。
默认情况下,您可以在 C++ 中做的最好的事情是:
Object getObject1()
return Object();
如果您真的必须使用动态分配,那么您的首选应该是按值返回std::unique_ptr
:
std::unique_ptr<Object> getObject1()
return std::make_unique<Object>();
请参阅 "GotW #90 Solution: Factories" by Herb Sutter 以获取有关该主题的精彩文章。除其他外,萨特说:
返回 unique_ptr 表示返回唯一所有权,即 纯“源”工厂函数的规范。 unique_ptr 在效率上无可匹敌 - 移动一个与移动/复制原始指针一样便宜。
至于你的具体问题:
我想第一种方法可能更快,
std::shared_ptr
涉及锁定以保证线程安全,因此它可能会降低性能。但是,这并不重要。动态分配通常总是比替代方案慢,因此您通常不想在微观性能重要的地方使用它(例如在紧密循环中或在每秒执行多次的代码的某些部分中)。 C++ 不鼓励您在免费商店中创建许多小对象。所以像这样的函数一开始就不应该成为瓶颈。
【讨论】:
这个问题我想了很久。到目前为止,我发现的所有解决方案在我看来都不理想。我希望它从使用的角度来看是简洁的,并且从提供的角度来看是可扩展的,但还不能找到一个完整的解决方案。在消费方面,我希望它看起来像 auto obj = ClassName::Create>(....) 或者你可以做 auto obj = ClassName::Create>(. ...)。在提供方面,您实现该分配器并将其与 unique_ptr 或 shared_ptr 或 local_val 或其他相关联。我还不能创建这样的模板。【参考方案2】:他们都是正确的。但是,为第一种情况创建一个“删除”函数是一个好习惯...
为什么?
因为您有一个负责分配对象的“接口”,那么您应该有另一对执行解除分配,一旦此函数的使用者使用您的接口,就不需要知道new
正在内部发生......它可能是 malloc
,例如,或其他任何东西......所以这对删除器函数将实现 delete
或 free
或任何其他你必须正确释放的东西。
【讨论】:
【参考方案3】:在这两个中,第二个将是首选。裸指针应该永远是你最后的选择。但理想情况下,您只需按值返回 Object
。如果做不到这一点,unique_ptr
会比shared_ptr
更好,除非您确实需要共享所有权。
我想第一种方法可能更快。
shared_ptr
可能是这样。但是使用unique_ptr
,编译器可以进行优化。手动删除的风险没有任何好处可以补偿您。
【讨论】:
+1 for “理想情况下,您只需按值返回Object
。”。不太熟悉 C++ 的人有时不会意识到按值返回对象通常是 optimised to eliminate temporary objects,因此比返回指向堆分配对象的指针更有效。
@BenCottrell 特别是在正确使用移动语义的情况下。它有时更有效,通常成本相等,而且很少更昂贵(假设设计合理的类)。即使在那些成本更高的罕见情况下,获得简单直观的值语义通常仍然值得。
@DavidSchwartz 你说:“裸指针应该永远是你的最后选择”,肯定有返回Object*
更好的情况。例如,当您不希望用户获得所有权时。
@DutChen18 我会先尝试其他所有方法,例如返回参考。
@DutChen18 在这种情况下,我更倾向于返回Object&
,如果我没有什么可返回的则抛出异常(而不是使用Object*
来返回nullptr
,因为我在返回 nullptr
时看到的最常见用法通常看起来像是一个隐身的错误返回代码)以上是关于函数是不是应该返回一个“新”对象的主要内容,如果未能解决你的问题,请参考以下文章