如何将 boost::atomic_store 与 shared_ptr<T> 和 shared_ptr<const T> 一起使用?
How to use boost::atomic_store with shared_ptr<T> and shared_ptr<const T>?
在我的例子中 T
是 pcl::PointCloud<pcl::PointXYZ>>
但问题应该代表任何类型 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);
问题是 boost::atomic_store
期望两个参数都是 T*
和 T
,但是尽管分配 [=25 是完全安全的,但它们被认为是不同的类型=] 到 const_p
。以下也不行。
boost::atomic_store(&const_p, const_cast<boost::shared_ptr<const pc> > (p));
尽管上面基本上将 pc*
转换为 const pc*
是完全安全的,但它会产生关于 const_cast
无法转换为不同类型的错误。我知道因为 pc
是模板参数,所以它被认为是 shared_ptr
类型的一部分,而不是 cv 限定条件。以下作品
boost::atomic_store(&const_p, boost::shared_ptr<const pc>(p));
但是,它创建了一个额外的不必要的boost::shared_ptr
。据我了解,boost::const_pointer_cast<const pc>(p)
也是如此,如果不再需要p
,则可以避免这种情况。
boost::atomic_store(&const_p, boost::shared_ptr<const pc>(std::move(p));
这仍然会创建一个额外的对象,但这无关紧要,因为引用计数没有被修改,由于是原子的,这是复制 shared_ptr
的昂贵部分。
碰巧这发生在我代码的非关键部分,所以我对上面的内容没问题,但我想知道以供将来参考:如果 std::move
不是一个选项,如何在没有创建不必要的临时指针的开销的情况下自动将 boost::shared_ptr<T>
存储到 boost::shared_ptr<const T>
?应该可以,因为通过 const T*
查看 T
是安全的,但我想不出办法。
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.
是的,这被称为 "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.
好吧,惊喜,你总能得到副本:
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 );
}
注意第二个参数是按值。这个,一下子解开了谜底:
#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?
你不能。这样看:load/store 是适合原子无锁实现的微不足道的操作。他们只做一件事,而且做得很好¹。
进行隐式转换不是该函数的职责。
我建议使用包装函数,甚至使用 ADL 从您自己的命名空间解决您自己的重载。
在我的例子中 T
是 pcl::PointCloud<pcl::PointXYZ>>
但问题应该代表任何类型 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);
问题是 boost::atomic_store
期望两个参数都是 T*
和 T
,但是尽管分配 [=25 是完全安全的,但它们被认为是不同的类型=] 到 const_p
。以下也不行。
boost::atomic_store(&const_p, const_cast<boost::shared_ptr<const pc> > (p));
尽管上面基本上将 pc*
转换为 const pc*
是完全安全的,但它会产生关于 const_cast
无法转换为不同类型的错误。我知道因为 pc
是模板参数,所以它被认为是 shared_ptr
类型的一部分,而不是 cv 限定条件。以下作品
boost::atomic_store(&const_p, boost::shared_ptr<const pc>(p));
但是,它创建了一个额外的不必要的boost::shared_ptr
。据我了解,boost::const_pointer_cast<const pc>(p)
也是如此,如果不再需要p
,则可以避免这种情况。
boost::atomic_store(&const_p, boost::shared_ptr<const pc>(std::move(p));
这仍然会创建一个额外的对象,但这无关紧要,因为引用计数没有被修改,由于是原子的,这是复制 shared_ptr
的昂贵部分。
碰巧这发生在我代码的非关键部分,所以我对上面的内容没问题,但我想知道以供将来参考:如果 std::move
不是一个选项,如何在没有创建不必要的临时指针的开销的情况下自动将 boost::shared_ptr<T>
存储到 boost::shared_ptr<const T>
?应该可以,因为通过 const T*
查看 T
是安全的,但我想不出办法。
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.
是的,这被称为 "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 forboost::const_pointer_cast<const pc>(p)
This can be avoided if p is no longer needed.
好吧,惊喜,你总能得到副本:
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 );
}
注意第二个参数是按值。这个,一下子解开了谜底:
#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?
你不能。这样看:load/store 是适合原子无锁实现的微不足道的操作。他们只做一件事,而且做得很好¹。
进行隐式转换不是该函数的职责。
我建议使用包装函数,甚至使用 ADL 从您自己的命名空间解决您自己的重载。