如何通过引用或按值返回智能指针(shared_ptr)? [英] How to return smart pointers (shared_ptr), by reference or by value?

查看:470
本文介绍了如何通过引用或按值返回智能指针(shared_ptr)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个方法返回 shared_ptr 的类。






    两个可能的线索:

    li> 早期对象破坏。如果我通过(const)引用返回 shared_ptr ,引用计数器不会递增,当该对象在另一个上下文(例如另一个线程)中超出范围时删除该对象。它是否正确?如果环境是单线程的,这种情况是否也会发生?
  • 成本。按值传递当然不是免费的。



感谢大家。

解决方案

按值返回智能指针



正如你所说,您将不会适当增加引用计数,这会打开在不正确的时间删除某些内容的风险。单单这应该是足够的理由不能通过参考返回。接口应该是健壮的。



由于返回值,现在的成本问题优化(RVO),因此您不会在现代编译器中产生递增 - 递减 - 递减序列或类似情况。因此,返回 shared_ptr 的最佳方法是简单地按值返回:

  shared_ptr< T> Foo()
{
return shared_ptr< T>(/ * getting something * /);
};

这是现代C ++编译器的一个显而易见的RVO机会。我知道一个事实,Visual C ++编译器实现RVO即使所有优化都关闭。使用C ++ 11的移动语义,这种关注甚至更少相关。



如果您还不确定,Dave Abrahams有文章,它通过值返回一个参数。我在这里重现一个片段;我强烈建议您阅读整篇文章:


诚实:以下代码如何让您感觉?

  std :: vector< std :: string> get_names(); 
...
std :: vector< std :: string> const names = get_names();

坦率地说,即使我应该知道得更好,原则上,当 get_names()
返回时,我们必须复制向量 c> string s。然后,当我们初始化
names 时,我们需要再次复制它,我们需要销毁第一个副本。如果在向量中有N string s,每个副本
可能需要多达N + 1个内存分配和一整个高速缓存不友好数据访问>作为字符串内容被复制。



不是面对那种焦虑,我经常回到pass-by-reference,以避免
不必要的副本:

  get_names(std :: vector< std :: string>& out_param); 
...
std :: vector< std :: string>名称;
get_names(names);

不幸的是,这种方法远非理想。




  • 代码增加了150%

  • 我们不得不放弃 const

  • 由于功能程序员喜欢提醒我们,突变使代码更复杂,因为它破坏了引用透明度和等式推理。

  • 我们不再有名称的严格值语义。



但是真的有必要弄乱我们的代码方式来提高效率?幸运的是,答案是没有(特别是如果你使用C ++ 0x)。



Let's say I have a class with a method that returns a shared_ptr.

What are the possible benefits and drawbacks of returning it by reference or by value?

Two possible clues:

  • Early object destruction. If I return the shared_ptr by (const) reference, the reference counter is not incremented, so I incur the risk of having the object deleted when it goes out of scope in another context (e.g. another thread). Is this correct? What if the environment is single-threaded, can this situation happen as well?
  • Cost. Pass-by-value is certainly not free. Is it worth avoiding it whenever possible?

Thanks everybody.

解决方案

Return smart pointers by value.

As you've said, if you return it by reference, you won't properly increment the reference count, which opens up the risk of deleting something at the improper time. That alone should be enough reason to not return by reference. Interfaces should be robust.

The cost concern is nowadays moot thanks to return value optimization (RVO), so you won't incur a increment-increment-decrement sequence or something like that in modern compilers. So the best way to return a shared_ptr is to simply return by value:

shared_ptr<T> Foo()
{
    return shared_ptr<T>(/* acquire something */);
};

This is a dead-obvious RVO opportunity for modern C++ compilers. I know for a fact that Visual C++ compilers implement RVO even when all optimizations are turned off. And with C++11's move semantics, this concern is even less relevant. (But the only way to be sure is to profile and experiment.)

If you're still not convinced, Dave Abrahams has an article that makes an argument for returning by value. I reproduce a snippet here; I highly recommend that you go read the entire article:

Be honest: how does the following code make you feel?

std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();

Frankly, even though I should know better, it makes me nervous. In principle, when get_names() returns, we have to copy a vector of strings. Then, we need to copy it again when we initialize names, and we need to destroy the first copy. If there are N strings in the vector, each copy could require as many as N+1 memory allocations and a whole slew of cache-unfriendly data accesses > as the string contents are copied.

Rather than confront that sort of anxiety, I’ve often fallen back on pass-by-reference to avoid needless copies:

get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );

Unfortunately, this approach is far from ideal.

  • The code grew by 150%
  • We’ve had to drop const-ness because we’re mutating names.
  • As functional programmers like to remind us, mutation makes code more complex to reason about by undermining referential transparency and equational reasoning.
  • We no longer have strict value semantics for names.

But is it really necessary to mess up our code in this way to gain efficiency? Fortunately, the answer turns out to be no (and especially not if you are using C++0x).

这篇关于如何通过引用或按值返回智能指针(shared_ptr)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆