如何在shared_ptr 和shared_ptr 中使用boost :: atomic_store?

[英]How to use boost::atomic_store with shared_ptr and shared_ptr?


In my case T is pcl::PointCloud<pcl::PointXYZ>> but the question shoud stand for any type T. The following example produces an error:

在我的情况下,T是pcl :: PointCloud >,但问题应该代表任何类型T.以下示例产生错误:

using pc = pcl::PointCloud<pcl::PointXYZ> >;
boost::shared_ptr<pc> p(new pc);
boost::shared_ptr<const pc> const_p(new pc);

// This is legal
const_p = p;

// The atomic equivalent is not
boost::atomic_store(&const_p, p);

The problem is that the boost::atomic_store expects both arguments to be T* and T, but these are considered different types despite the fact that it's perfectly safe to assign p to const_p. The following doesn't work either.

问题是boost :: atomic_store期望两个参数都是T *和T,但是这些被认为是不同的类型,尽管将p分配给const_p是完全安全的。以下也不起作用。

boost::atomic_store(&const_p, const_cast<boost::shared_ptr<const pc> > (p));

Despite the above basically casting a pc* to const pc* which is perfectly safe, it produces an error about const_cast not being able to convert to different type. I understand that because pc is a template argument, it is considered part of the type of the shared_ptr and not a cv qualification. The following work

尽管上面基本上将pc *转换为const pc *,这是非常安全的,但它会产生一个关于const_cast无法转换为不同类型的错误。我理解,因为pc是模板参数,它被认为是shared_ptr类型的一部分,而不是cv限定。以下工作

boost::atomic_store(&const_p, boost::shared_ptr<const pc>(p));

However, it creates an extra unecessary boost::shared_ptr. It is my understanding that the same is true for boost::const_pointer_cast<const pc>(p) This can be avoided if p is no longer needed.

但是,它会创建一个额外的不必要的boost :: shared_ptr。我的理解是对于boost :: const_pointer_cast (p)也是如此。如果不再需要p,可以避免这种情况。

boost::atomic_store(&const_p, boost::shared_ptr<const pc>(std::move(p));

This still creates an extra object but it shouldn't matter because the reference count is not modified, which is the expensive part of copying a shared_ptr on account of being atomic.

这仍然会创建一个额外的对象,但它并不重要,因为引用计数没有被修改,这是复制shared_ptr由于是原子的昂贵部分。

It just so happens that this occurs in a non-critical part of my code so I'm fine with the above, but I would like to know for future reference: If std::move was not an option, how would one atomically store a boost::shared_ptr<T> to a boost::shared_ptr<const T> without the overhead of creating an unecessary temporary pointer? It should be possible because it is safe to view a T through a const T*, but I can't figure out a way to do it.

恰好这种情况发生在我的代码的非关键部分,所以我对上面的内容很好,但我想知道将来的参考:如果std :: move不是一个选项,那么如何以原子方式存储boost :: shared_ptr 一个boost :: shared_ptr 没有创建一个不必要的临时指针的开销吗?它应该是可能的,因为通过const T *查看T是安全的,但我无法找到一种方法。

1 个解决方案

#1


2  

I understand that because pc is a template argument, it is considered part of the type of the shared_ptr and not a cv qualification.

我理解,因为pc是模板参数,它被认为是shared_ptr类型的一部分,而不是cv限定。

Yes, this is known as "non-deducible context".

是的,这被称为“不可推翻的背景”。

The following work

以下工作

boost::atomic_store(&const_p, boost::shared_ptr<const pc>(p));

However, it creates an extra unecessary boost::shared_ptr. It is my understanding that the same is true for boost::const_pointer_cast<const pc>(p) This can be avoided if p is no longer needed.

但是,它会创建一个额外的不必要的boost :: shared_ptr。我的理解是对于boost :: const_pointer_cast (p)也是如此。如果不再需要p,可以避免这种情况。

Well, surprise, you always get the copy:

好吧,惊喜,你总是得到副本:

template<class T> void atomic_store( shared_ptr<T> * p, shared_ptr<T> r ) BOOST_SP_NOEXCEPT
{
    boost::detail::spinlock_pool<2>::scoped_lock lock( p );
    p->swap( r );
}

Note the second parameter is by value. This, at once, solves the mystery:

注意第二个参数是按值。这一点,解决了这个谜团:

Live On Coliru

住在科利鲁

#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 
#include <boost/atomic.hpp>

namespace pcl {
    struct PointXYZ {};
    template <typename P> struct PointCloud {
    };
}

int main() {
    using pc = pcl::PointCloud<pcl::PointXYZ>;
    boost::shared_ptr<pc> p             = boost::make_shared<pc>();
    boost::shared_ptr<const pc> const_p = boost::make_shared<pc>();

    // This is legal
    const_p = p;

    // The atomic equivalent is too
    boost::atomic_store<pc const>(&const_p, p);
}

If std::move was not an option, how would one atomically store a boost::shared_ptr to a boost::shared_ptr without the overhead of creating an unecessary temporary pointer?

如果std :: move不是一个选项,那么如何将boost :: shared_ptr原子地存储到boost :: shared_ptr而不会产生创建不必要的临时指针的开销?

You can't. Look at it this way: load/store are meant to be trivial operations amenable to atomic lockfree implementations. They do 1 thing, and they do it well¹.

你不能。以这种方式看待它:加载/存储意味着可以执行原子锁定实现的简单操作。他们做了一件事,他们做得很好¹。

Doing implicit conversions is just not the responsibility of that function.

进行隐式转换不是该函数的责任。

I'd suggest using a wrapper function, or even using ADL to resolve your own overload from your own namespace.

我建议使用包装器函数,甚至使用ADL从您自己的命名空间中解析自己的重载。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.itdaan.com/blog/2017/09/11/16eaaa917cf5c38c528562f67407e9de.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号