手动Unref
我对Boost的侵入式指针有一个问题。它的 布尔转换运算符 检查 x.get() != 0
。但是,下面的代码在标记点处失败。为什么会这样?
我猜我可能与这个事实有关 delete
没有设置指针 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;
}
(架构:Darwin 10.7,测试编译器g ++ 4.7和4.6 with -std=c++11
)
参考到指针
通过源代码除草后 intrusive_ptr<T>
,我发现只有一个电话 intrusive_ptr_release
在析构函数中:
~intrusive_ptr()
{
if( px != 0 ) intrusive_ptr_release( px );
}
自从争论 px
类型 T*
是一个左值,应该可以通过稍微改变函数签名将其设置为零 intrusive_ptr_release
:
inline void intrusive_ptr_release(T*& p)
{
if (--p->count == 0u)
{
delete p;
p = 0;
}
}
直观地说,这个指针引用指针参数应该赋值的左值 p
在调用语境中为0. Bjarne也 提到这个成语。然而,断言仍然在标记线处失败,这次让我无能为力。
示例用法
我手动修改和取消指针的原因是我必须在将原始指针传递给C API时使用一段时间。这意味着我必须在将它传递给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);
}
这里,第二个参数在构造中 y
在 g()
从C API返回指针时避免使用ref,这会补偿手动引用 f()
。
我意识到手动不提供侵入式指针会导致意外行为,而这种用法看起来很好。