本文介绍了传递const shared_ptr< T&与仅shared_ptr< T>作为参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当应用程序中涉及智能指针时,我已经阅读了很多有关性能问题的讨论.常见的建议之一是将智能指针传递为const& amp;.而不是像这样的副本:

I've been reading quite a number of discussions about performance issues when smart pointers are involved in an application. One of the frequent recommendations is to pass a smart pointer as const& instead of a copy, like this:

void doSomething(std::shared_ptr<T> o) {}

void doSomething(const std::shared_ptr<T> &o) {}

但是,第二个变体是否真的没有达到共享指针的目的?实际上,我们在这里共享共享指针,因此,如果由于某种原因在调用代码中释放了该指针(考虑重新进入或产生副作用),则const指针将变为无效.共享指针实际上应防止的情况.我了解const&由于不涉及复制且无需锁定即可管理引用计数,因此节省了一些时间.但是代价是使代码的安全性降低了,对吧?

However, doesn't the second variant actually defeat the purpose of a shared pointer? We are actually sharing the shared pointer here, so if for some reasons the pointer is released in the calling code (think of reentrancy or side effects) that const pointer becomes invalid. A situation the shared pointer actually should prevent. I understand that const& saves some time as there is no copying involved and no locking to manage the ref count. But the price is making the code less safe, right?

推荐答案

通过 const& 传递 shared_ptr 的优点是引用计数不必被增加然后减少.因为这些操作必须是线程安全的,所以它们可能很昂贵.

The advantage of passing the shared_ptr by const& is that the reference count doesn't have to be increased and then decreased. Because these operations have to be thread-safe, they can be expensive.

您说得很对,您可能会拥有一连串的传票,以供日后参考.在一个具有现实后果的现实世界项目中,我曾经发生过这种情况.一个函数在容器中找到 shared_ptr 并将其引用传递给调用堆栈.调用堆栈深处的一个函数从容器中删除了该对象,导致所有引用突然引用了不再存在的对象.

You are quite right that there is a risk that you can have a chain of passes by reference that later invalidates the head of the chain. This happened to me once in a real-world project with real-world consequences. One function found a shared_ptr in a container and passed a reference to it down a call stack. A function deep in the call stack removed the object from the container, causing all the references to suddenly refer to an object that no longer existed.

因此,当您通过引用传递某些内容时,调用者必须确保它在函数调用的生命周期内仍然存在.如果这是个问题,请不要使用通过引用.

So when you pass something by reference, the caller must ensure it survives for the life of the function call. Don't use a pass by reference if this is an issue.

(我假设您有一个用例,其中有一些特定原因要通过 shared_ptr 而不是通过引用来传递.最常见的此类原因是所调用的函数可能需要扩展对象的寿命.)

(I'm assuming you have a use case where there's some specific reason to pass by shared_ptr rather than by reference. The most common such reason would be that the function called may need to extend the life of the object.)

更新:针对感兴趣的人的错误的更多详细信息:该程序具有共享的对象并实现了内部线程安全.它们被装在容器中,延长功能寿命是很常见的.

Update: Some more details on the bug for those interested: This program had objects that were shared and implemented internal thread safety. They were held in containers and it was common for functions to extend their lifetimes.

这种特定类型的对象可以存在于两个容器中.一种在活动时,另一种在不活动时.有些操作对活动对象起作用,有些对无效对象起作用.当在非活动对象上接收到使该命令处于活动状态的命令而该对象的唯一 shared_ptr 由非活动对象的容器保存时,就会发生错误情况.

This particular type of object could live in two containers. One when it was active and one when it was inactive. Some operations worked on active objects, some on inactive objects. The error case occurred when a command was received on an inactive object that made it active while the only shared_ptr to the object was held by the container of inactive objects.

非活动对象位于其容器中.通过引用将对容器中 shared_ptr 的引用传递给命令处理程序.通过引用链,此 shared_ptr 最终到达了意识到这是一个必须激活的非活动对象的代码.该对象已从非活动容器中移除(这破坏了非活动容器的 shared_ptr ),并添加到了活动容器中(这又添加了对传递给"add"的 shared_ptr 的引用.常规).

The inactive object was located in its container. A reference to the shared_ptr in the container was passed, by reference, to the command handler. Through a chain of references, this shared_ptr ultimately got to the code that realized this was an inactive object that had to be made active. The object was removed from the inactive container (which destroyed the inactive container's shared_ptr) and added to the active container (which added another reference to the shared_ptr passed to the "add" routine).

在这一点上,存在的对象唯一的 shared_ptr 可能是非活动容器中的对象.调用堆栈中的所有其他函数都只引​​用了它.当从非活动容器中删除对象时,该对象可能会被破坏,所有这些引用都指向一个不再存在的 shared_ptr .

At this point, it was possible that the only shared_ptr to the object that existed was the one in the inactive container. Every other function in the call stack just had a reference to it. When the object was removed from the inactive container, the object could be destroyed and all those references were to a shared_ptr that that no longer existed.

解开这个花了大约一个月的时间.

It took about a month to untangle this.

这篇关于传递const shared_ptr&lt; T&amp;与仅shared_ptr&lt; T&gt;作为参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-01 12:49