C ++ - 引用传递到std :: shared_ptr的或升压:: shared_ptr的 [英] C++ - passing references to std::shared_ptr or boost::shared_ptr

查看:253
本文介绍了C ++ - 引用传递到std :: shared_ptr的或升压:: shared_ptr的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有需要一起工作的函数的的shared_ptr ,那岂不是更有效的传递给它的引用(所以要避免复制的shared_ptr )对象?
可能是什么不好的副作用?
我设想两种可能的情况:

If I have a function that needs to work with a shared_ptr, wouldn't it be more efficient to pass it a reference to it (so to avoid copying the shared_ptr object)? What are the possible bad side effects? I envision two possible cases:

1)函数内部副本在

ClassA::take_copy_of_sp(boost::shared_ptr<foo> &sp)  
{  
     ...  
     m_sp_member=sp; //This will copy the object, incrementing refcount  
     ...  
}  

2)函数内部的参数,才使用像

2) inside the function the argument is only used, like in

Class::only_work_with_sp(boost::shared_ptr<foo> &sp) //Again, no copy here  
{    
    ...  
    sp->do_something();  
    ...  
}  

按值而不是按引用;

我不能在这两种情况下看到一个很好的理由来打发的boost :: shared_ptr的&LT;富过夜。按值传递不仅将暂时增加引用计数由于复制,然后退出函数作用域时递减它。
我俯瞰的东西吗?

I can't see in both cases a good reason to pass the boost::shared_ptr<foo> by value instead of by reference. Passing by value would only "temporarily" increment the reference count due to the copying, and then decrement it when exiting the function scope. Am I overlooking something?

只是为了澄清,看完几个答案后:我的premature优化的担忧完全同意,我总是尽量先姿态 - 当时工作的最热点。我的问题是更多的从纯技术code点的视图,如果你知道我的意思。

Just to clarify, after reading several answers: I perfectly agree on the premature-optimization concerns, and I always try to first-profile-then-work-on-the-hotspots. My question was more from a purely technical code-point-of-view, if you know what I mean.

推荐答案

鲜明的的shared_ptr 实例的目的是保证(尽可能)只要这个的shared_ptr 在范围,对象指向仍然会存在,因为它的引用计数将至少为1。

The point of a distinct shared_ptr instance is to guarantee (as far as possible) that as long as this shared_ptr is in scope, the object it points to will still exist, because its reference count will be at least 1.

Class::only_work_with_sp(boost::shared_ptr<foo> sp)
{
    // sp points to an object that cannot be destroyed during this function
}

因此​​,通过使用一个参考的shared_ptr ,您禁用的保证。因此,在你的第二个案例:

So by using a reference to a shared_ptr, you disable that guarantee. So in your second case:

Class::only_work_with_sp(boost::shared_ptr<foo> &sp) //Again, no copy here  
{    
    ...  
    sp->do_something();  
    ...  
}

你怎么知道 SP-&GT; do_something()不会炸毁由于空指针

这一切都取决于什么是在code的那些'...'的部分。如果你在一个具有(在code的另一部分地方)清理的的shared_ptr 的副作用与第一'...'叫什么同一个对象?如果它发生了什么是仅存的不同的shared_ptr 到该对象?再见对象,只是在那里你将要尝试并使用它。

It all depends what is in those '...' sections of the code. What if you call something during the first '...' that has the side-effect (somewhere in another part of the code) of clearing a shared_ptr to that same object? And what if it happens to be the only remaining distinct shared_ptr to that object? Bye bye object, just where you're about to try and use it.

因此​​,有两种方法来回答这个问题:

So there are two ways to answer that question:


  1. 非常谨慎,直到你确信函数体中对象不会死检查整个程序的源代码。

  1. Examine the source of your entire program very carefully until you are sure the object won't die during the function body.

更改参数后面是一个不同的对象,而不是一个参考。

Change the parameter back to be a distinct object instead of a reference.

建议总有点此处适用:甭管让您code为性能而变化的风险,直到你定时测量你的产品在实际情况中探查和决定性的改变你想将对性能显著差异

General bit of advice that applies here: don't bother making risky changes to your code for the sake of performance until you've timed your product in a realistic situation in a profiler and conclusively measured that the change you want to make will make a significant difference to performance.

更新评议JQ

下面是一个人为的例子。这是刻意简单,所以不慎就会很明显。在实际的例子,因为它是隐藏在真实的细节层的错误是不那么明显了。

Here's a contrived example. It's deliberately simple, so the mistake will be obvious. In real examples, the mistake is not so obvious because it is hidden in layers of real detail.

我们有将某处发送信息的功能。这可能是一个大的消息,因此,而不是使用的std ::字符串,由于它是围绕传递到多个地方有可能被复制,我们使用了 shared_ptr的来的字符串:

We have a function that will send a message somewhere. It may be a large message so rather than using a std::string that likely gets copied as it is passed around to multiple places, we use a shared_ptr to a string:

void send_message(std::shared_ptr<std::string> msg)
{
    std::cout << (*msg.get()) << std::endl;
}

(我们只是发送就到控制台在这个例子中)。

(We just "send" it to the console for this example).

现在我们想添加一个设施记住previous消息。我们希望以下行为:一个变量必须存在一个包含最近发送的消息,但在目前正在发送的信息则必须没有previous消息(变量应在发送之前进行复位)。因此,我们宣布新的变量:

Now we want to add a facility to remember the previous message. We want the following behaviour: a variable must exist that contains the most recently sent message, but while a message is currently being sent then there must be no previous message (the variable should be reset before sending). So we declare the new variable:

std::shared_ptr<std::string> previous_message;

然后,我们根据我们指定的规则修改我们的函数

void send_message(std::shared_ptr<std::string> msg) { previous_message = 0; std::cout << *msg << std::endl; previous_message = msg; }

So, before we start sending we discard the current previous message, and then after the send is complete we can store the new previous message. All good. Here's some test code:

所以,在我们开始发送,我们放弃当前的previous消息,然后发送完成后,我们可以存储新的previous消息。都好。下面是一些测试code:

send_message(std::shared_ptr<std::string>(new std::string("Hi"))); send_message(previous_message);

And as expected, this prints Hi! twice.

和预期的一样,这个印刷你好!两次。

现在走来维护者先生,谁着眼于code和认为:嘿,那参数 send_message 的shared_ptr

void send_message(std::shared_ptr<std::string> msg)

Obviously that can be changed to:

显然,可以更改为:

void send_message(const std::shared_ptr<std::string> &msg)

Think of the performance enhancement this will bring! (Never mind that we're about to send a typically large message over some channel, so the performance enhancement will be so small as to be unmeasureable).

想想性能增强,这将带来! (没关系,我们即将通过一些渠道发送一个典型的大消息,这样的性能提升会那么小到unmeasureable)。

But the real problem is that now the test code will exhibit undefined behaviour (in Visual C++ 2010 debug builds, it crashes).

但真正的问题是,现在的测试code将表现出不确定的行为(在Visual C ++ 2010调试版本,它崩溃)。

Mr Maintainer is surprised by this, but adds a defensive check to send_message in an attempt to stop the problem happening:

维护者先生是感到意外,但在试图阻止问题发生增加了一个防守检查 send_message

void send_message(const std::shared_ptr<std::string> &msg) { if (msg == 0) return;

But of course it still goes ahead and crashes, because msg is never null when send_message is called.

但是,当然,它仍然继续并崩溃,因为信息 send_message 被称为永远不能为null。

As I say, with all the code so close together in a trivial example, it's easy to find the mistake. But in real programs, with more complex relationships between mutable objects that hold pointers to each other, it is easy to make the mistake, and hard to construct the necessary test cases to detect the mistake.

正如我所说,所有的code如此接近的一个简单的例子在一起,很容易发现其中的错误。但是在实际程序中,与该保持指向彼此可变对象之间更复杂的关系,它是很容易的使的错误,并且很难构建必要的测试用例来检测错误。

最简单的解决方案,其中你想有一个功能是能够依靠一个的shared_ptr 继续在整个非空,是分配自己的真正功能的shared_ptr ,而不是依靠一个参考现有的shared_ptr

The easy solution, where you want a function to be able to rely on a shared_ptr continuing to be non-null throughout, is for the function to allocate its own true shared_ptr, rather than relying on a reference to an existing shared_ptr.

缺点是复制了的shared_ptr 不是免费的:即使是无锁的实现必须使用互锁操作尊敬线程保证。所以有可能情况下的程序可以通过更改的shared_ptr 的shared_ptr和放大器显著加快; 。但是,这不是一个可以对所有程序安全地所做的更改。它改变了程序的逻辑意义。

The downside is that copied a shared_ptr is not free: even "lock-free" implementations have to use an interlocked operation to honour threading guarantees. So there may be situations where a program can be significantly sped up by changing a shared_ptr into a shared_ptr &. But it this is not a change that can be safely made to all programs. It changes the logical meaning of the program.

请注意,如果我们使用的std :: string的贯穿而不是的std :: shared_ptr的&LT将发生类似的错误;的std :: string的&GT; ,取而代之的:

Note that a similar bug would occur if we used std::string throughout instead of std::shared_ptr<std::string>, and instead of:

previous_message = 0;

要清除该消息,我们说:

to clear the message, we said:

previous_message.clear();

然后症状会意外发送,而不是未定义行为空消息。一个非常大的字符串的额外副本的成本可能是很多比复制一个的shared_ptr ,所以权衡可能是不同的成本更显著。

Then the symptom would be the accidental sending of an empty message, instead of undefined behaviour. The cost of an extra copy of a very large string may be a lot more significant than the cost of copying a shared_ptr, so the trade-off may be different.

这篇关于C ++ - 引用传递到std :: shared_ptr的或升压:: shared_ptr的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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