mav*_*vam 11 c++ boost memory-management smart-pointers c++11
我对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;
}
Run Code Online (Sandbox Code Playgroud)
(架构:Darwin 10.7,测试编译器g ++ 4.7和4.6 -std=c++11)
除草了源代码之后intrusive_ptr<T>,我发现intrusive_ptr_release在析构函数中只有一个调用:
~intrusive_ptr()
{
if( px != 0 ) intrusive_ptr_release( px );
}
Run Code Online (Sandbox Code Playgroud)
由于pxtype 的参数T*是左值,因此可以通过稍微更改以下函数签名将其设置为零intrusive_ptr_release:
inline void intrusive_ptr_release(T*& p)
{
if (--p->count == 0u)
{
delete p;
p = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
直观地说,这个指针引用指针参数应该将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);
}
Run Code Online (Sandbox Code Playgroud)
这里,构造yin中的第二个参数在g()从C API返回指针时避免了ref,这补偿了手动ref f().
我意识到手动不提供侵入式指针会导致意外行为,而这种用法似乎很好.
sel*_*tze 13
问题是:为什么期望x最终转换为false?你以意想不到的方式搞乱了参考柜台!即使仍然存在intrusive_ptr指向对象的-x,您也将它降低到零.这不是它的工作原理.ref计数器应该至少与intrusive_ptr指向ref计数对象的对象数量一样大- 否则它不会是ref计数器,是吗?