手动取消引用
我对Boost的侵入式指针有一个问题。这是boolean conversion operator checks x.get() != 0但是,下面的代码在标记点失败。为什么会这样呢?
我猜我可能与delete does not set a pointer to 0 (或nullptr)的事实有关。如果不是这样,我怎么能有效地使用介入式指针呢?我希望能够像常规指针一样使用介入式指针,例如,在表达式x && x->foo()中,但这个人工制品似乎排除了它。
#include <atomic>
#include <boost/intrusive_ptr.hpp>
struct T
{
T() : count(0u) { }
size_t ref_count()
{
return count;
}
std::atomic_size_t count;
};
void intrusive_ptr_add_ref(T* p)
{
++p->count;
}
void intrusive_ptr_release(T* p)
{
if (--p->count == 0u)
delete p;
}
int main()
{
boost::intrusive_ptr<T> x;
x = new T;
assert(x->ref_count() == 1);
auto raw = x.get();
intrusive_ptr_add_ref(raw);
intrusive_ptr_add_ref(raw);
assert(x->ref_count() == 3);
intrusive_ptr_release(raw);
intrusive_ptr_release(raw);
assert(x->ref_count() == 1);
intrusive_ptr_release(raw); // Destroys T, ref_count() == 0.
assert(! x); // Fails.
return 0;
}(架构:Darwin10.7,使用-std=c++11测试编译器g++ 4.7和4.6 )
指向指针的引用
在清理了intrusive_ptr<T>的源代码后,我发现析构函数中只有一次对intrusive_ptr_release的调用:
~intrusive_ptr()
{
if( px != 0 ) intrusive_ptr_release( px );
}由于T*类型的参数px是一个左值,因此应该可以通过稍微更改intrusive_ptr_release的函数签名将其设置为零
inline void intrusive_ptr_release(T*& p)
{
if (--p->count == 0u)
{
delete p;
p = 0;
}
}直观地说,这个指向指针的指针引用参数应该将调用上下文中的p的左值赋值为0。Bjarne也叫mentions this idiom。但是,断言仍然在标记的行处失败,这一次让我一无所知。
示例用法
我手动引用和取消引用指针的原因是,在将原始指针传递给C时,我必须使用它一段时间。这意味着我必须在将它传递给C API之前引用它,以防止破坏,并在我取回它时从原始指针重新创建一个介入式指针。下面是一个示例:
void f()
{
intrusive_ptr<T> x = new T;
auto raw = x.get();
intrusive_ptr_add_ref(raw);
api_in(raw);
}
void g()
{
T* raw = api_out();
intrusive_ptr<T> y(raw, false);
h(y);
}在这里,在g()中构造y的第二个参数避免了从C API获取指针时的引用,这补偿了f()中的手动引用。
我意识到手动取消引用侵入式指针可能会导致意外的行为,而这种用法似乎没有问题。
发布于 2012-03-26 15:59:06
问题是:为什么你希望x在最后转换为false?你正在以意想不到的方式摆弄裁判计数器!即使仍然有一个指向该对象的intrusive_ptr -x-,您也会将它减少到零。这不是它的工作方式。引用计数器应该至少与指向引用计数对象的intrusive_ptr对象的数量一样大-否则它就不是引用计数器了,不是吗?
发布于 2012-03-25 08:42:07
阅读intrusive_ptr上的文档,我发现使用自己的术语“销毁”对象与指针为0之间没有任何联系。因此,如果你想使用x && x->foo()的习惯用法,你的intrusive_ptr_release函数也应该将指针设置为0。
我可以在intrusive_ptr中看到设计决策。当调用intrusive_ptr_release时,应该只执行销毁,不包括delete提供的行为以外的任何其他行为,所以如果您还想将指针放到0以支持该习惯用法,则必须在该函数的代码中执行此操作,但intrusive_ptr本身不会强制您包含比delete本身更多的限制:也就是说,它不会强制您将指针重置为0。
https://stackoverflow.com/questions/9856893
复制相似问题