使用member_hook的Boost.Intrusive push_back为何与原对象地址不匹配?
为何使用
list_member_hook<>的Boost Intrusive链表断言会失败? 以下是出现问题的代码:
#include <boost/intrusive/list.hpp> #include <cassert> using namespace boost::intrusive; class A { public: int i_; A(int i) : i_(i) {}; list_member_hook<> m_hook1; }; typedef list<A, member_hook<A, list_member_hook<>, &A::m_hook1> > List1; int main() { List1 list1; A *a = new A(10); list1.push_back(*a); assert( a == &list1.back()); // 断言失败,原因是什么? return 0; }
问题描述:将动态分配的对象a通过push_back加入链表list1后,断言a与&list1.back()相等失败,请问原因是什么?
原因分析
问题出在list_member_hook<>的默认链接模式上:它默认使用link_mode<auto_unlink>。这种模式为了实现对象析构时自动从链表解绑的功能,会修改hook内部的指针值。
Boost Intrusive链表的元素访问依赖于从hook地址反向计算所属对象的地址。当auto_unlink模式修改了hook的指针后,这个反向计算逻辑会出错,导致list1.back()返回的对象地址和原指针a不匹配,断言因此失败。
解决方法
修改list_member_hook的模板参数,指定不修改hook指针的链接模式即可,比如safe_link或normal_link:
class A { public: int i_; A(int i) : i_(i) {}; // 使用safe_link模式,支持安全的自动解绑且不破坏地址计算 list_member_hook<link_mode<safe_link>> m_hook1; };
或者选择normal_link模式(无自动解绑,需手动管理对象在链表中的生命周期):
list_member_hook<link_mode<normal_link>> m_hook1;
修改后,hook内部指针不会被修改,通过list1.back()获取的对象地址会和原指针a完全一致,断言即可通过。
内容的提问来源于stack exchange,提问作者Alex Net
相关产品推荐
相关产品推荐

