悬挂指针与boost::weak_ptr

本文探讨了C++中悬挂指针引起的问题及如何利用boost::weak_ptr解决这些问题,确保指针的有效性。
2007年10月12日 01:23:00

  与内存泄露相比,C++最令人头痛的问题是内存越界,而内存越界很多情况下是由于悬挂指针引起的。  
  假设一个指针变量:
  Object * ptr;
  使用ptr时,我们除了要判断ptr是否为0以外,还要怀疑它指向的对象是否有效,是不是已经在别的地方被销毁了。我们希望当它指向的对象被销毁时,ptr被自动置为0。
  显然,C++没有这种机制,但是,可以借助于boost::weak_ptr做到这一点。

inline void null_deleter(void const * )
{
}

class X
{
private :

shared_ptr
> X < this_;
int i_;

public :

explicit X( int i): this_(this, & null_deleter), i_(i)
{
}

X(X
const & rhs): this_(this, & null_deleter), i_(rhs.i_)
{
}

X
& operator = (X const & rhs)
{
i_
= rhs.i_;
}

weak_ptr
> X < weak_this() const { return this_; }
};




定义变量:
weak_ptr>X< ptr = x.weak_this(); // x为一个X 对象

则当 x 被销毁时,ptr 被自动置为无效。使用方法如下:

if ( shard_ptr>X< safePtr = ptr.lock() ) safePtr-

这 种办法用于单线程中,因为 x 对象可能是基于栈分配的。如果需要在多线程中访问X对象,那么最好的办法还是使用shared_ptr 来管理对象的生命期。这样的话,对于safePtr, 可以保证在 safePtr 的生命期内,它所指向的对象不会被其它线程删除。

Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=1821035


### Boost UDP Server 中 `tr1::bad_weak_ptr` 异常的处理 在使用 Boost.Asio 开发 UDP 服务器时,若通过 `shared_from_this()` 启动异步操作,可能会遇到如下异常信息: ``` terminate called after throwing an instance of 'std::bad_weak_ptr' what(): bad_weak_ptr Aborted ``` 该异常通常表明在对象尚未绑定到 `shared_ptr` 之前调用了 `shared_from_this()`,导致无法正确获取共享指针Boost.Asio 的异步模型依赖于对象生命周期管理机制,因此必须确保异步操作期间对象不会被提前销毁[^2]。 #### 原因分析解决方法 ##### 1. 对象未通过 `shared_ptr` 管理即调用 `shared_from_this()` `shared_from_this()` 只能在已经被 `shared_ptr` 所管理的对象中安全调用。如果直接使用原始指针构造对象并调用该方法,将抛出 `bad_weak_ptr` 异常。例如: ```cpp udp_server server(io); // 错误:未使用 shared_ptr server.do_send(); ``` 正确的做法是通过静态工厂函数创建对象,并返回 `shared_ptr` 实例[^3]: ```cpp class udp_server : public boost::enable_shared_from_this<udp_server> { public: static boost::shared_ptr<udp_server> create(boost::asio::io_context& io) { return boost::shared_ptr<udp_server>(new udp_server(io)); } }; ``` ##### 2. 在构造函数中启动异步操作时调用 `shared_from_this()` 若在构造函数内部立即调用 `async_*` 方法并传入 `shared_from_this()`,此时对象尚未完全构造完毕,也可能引发 `bad_weak_ptr` 异常。应避免在构造函数中直接启动异步操作,而应在构造完成后再触发相关逻辑。 示例错误代码: ```cpp udp_server(boost::asio::io_context& io) : socket_(io, udp::endpoint(udp::v4(), 12345)) { do_receive(shared_from_this()); // 错误:构造函数中调用 shared_from_this() } ``` 正确方式应为构造完成后手动调用启动函数: ```cpp udp_server(boost::asio::io_context& io) : socket_(io, udp::endpoint(udp::v4(), 12345)) {} void start() { do_receive(); } ``` ##### 3. 多线程环境下未正确管理对象生命周期 当多个线程并发执行异步操作时,若未确保对象始终由 `shared_ptr` 管理,可能导致对象提前释放。建议在所有异步操作回调中捕获 `shared_from_this()`,以延长对象生命周期直至异步操作完成[^1]。 例如,在 `do_send()` 函数中保持对 `shared_from_this()` 的引用: ```cpp void do_send() { auto self(shared_from_this()); const std::string& message = send_queue_.front().first; const udp::endpoint& endpoint = send_queue_.front().second; socket_.async_send_to(boost::asio::buffer(message), endpoint, [this, self](const boost::system::error_code& ec, std::size_t /*bytes_sent*/) { std::lock_guard<std::mutex> lock(queue_mutex_); send_queue_.pop_front(); if (!send_queue_.empty()) { do_send(); } }); } ``` #### 示例修复后的完整构造函数和启动流程 ```cpp explicit udp_server(boost::asio::io_context& io) : socket_(io, udp::endpoint(udp::v4(), 12345)) {} void start() { do_receive(); } void do_receive() { socket_.async_receive_from( boost::asio::buffer(recv_buffer_), remote_endpoint_, boost::bind(&udp_server::handle_receive, shared_from_this(), _1, _2)); } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值