找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 5523|回复: 0

boost.enable_shared_from_this和boost.shared_ptr的使用

[复制链接]
发表于 2011-3-17 00:34:46 | 显示全部楼层 |阅读模式
boost.enable_shared_from_this结合boost.shared_ptr似乎非常完美, 其实不然,
使用它还是需要注意很多地方, 如果不注意, 那也将会导致致命性的错误.

1. 首先enable_shared_from_this不能在构造函数中使用.

show code:
  1. class tester
  2.     : public boost::enable_shared_from_this<tester>
  3. {
  4. public:
  5.     tester()
  6.     {
  7.         boost::shared_ptr<tester> sp = shared_from_this(); // 错误的使用!!!
  8.     }
  9. };
复制代码
2. 析构函数执行时, 析构函数内部不能调用shared_from_this(); 并且其它线程也不能再使用shared_from_this();

show code
  1. class tester
  2.     : public boost::enable_shared_from_this<tester>
  3. {
  4. public:
  5.     tester()
  6.     {
  7.         // boost::shared_ptr<tester> sp = shared_from_this(); // 错误的使用!!!
  8.     }
  9.     ~tester()
  10.     {
  11.         Sleep(0xFFFFFFFF); // 析构一直不退出.
  12.     }
  13.     void start()
  14.     {
  15.         boost::shared_ptr<tester> ts;
  16.         boost::thread t1(boost::bind(&tester::operation, this, boost::ref(ts)));
  17.     }
  18.     void operation(boost::shared_ptr<tester>& sp)
  19.     {
  20.         for (;;)
  21.         {
  22.             // 线程中使用shared_from_this()!!!
  23.             // 当这个对象的生命期到了结束时(还未结束),
  24.             // 执行析构函数时, 这里将导致错误!!!
  25.             // 也就是说, 只要对象执行到析构函数, 无论如何
  26.             // 都不能再调用这个对象的shared_from_this!
  27.             sp = shared_from_this();
  28.             Sleep(100);
  29.         }
  30.     }
  31. };
  32. int main(int argc, char* argv[])
  33. {
  34.     boost::shared_ptr<tester> sp(new tester);
  35.     sp->start();
  36.     return 0;
  37. }
复制代码
还有好几种情况, 有空全部总结下, 并把原因也列出来.

总之如果实在难以把握的话, 又要把在中间this一样的智能指针的时候, 还是使用boost.intrusive_ptr吧, 还有就是COM指针也可以boost.intrusive_ptr来包装,或者也可以使用shared_ptr直接如下:

show code:
  1. template <class _RawComPtr>
  2. boost::shared_ptr<_RawComPtr> make_shared_from_COM(_RawComPtr * p)
  3. {
  4.     p->AddRef();
  5.     boost::shared_ptr<_RawComPtr> pw(p, boost::mem_fn(&_RawComPtr::Release));
  6.     return pw;
  7. }
复制代码
这样写成一个模板,似乎也是很不错的做法。类似的包装像FILE*这样的也非常方便,如:

show code:
  1. boost::shared_ptr<FILE> spfile(fopen("c:\\test.dat", "w+b"), fclose);
  2. // 写时可以:
  3. fwrite(buf, n, n, >(*spfile));
  4. // 或:
  5. fwrite(buf, n, n, spfile.get());
  6. // 这样就会当智能指针撤消时,自动fclose掉这个文件。当然也可以写删除器来完成。不过最简单就简单些吧。
复制代码
另外,更值得推荐的就是使用它来做"Pimpl",这种做法在许多的质量比较高的开源库里广泛使用,如libtorrent等...类似的代码像:
show code:
  1. // file.hpp:
  2. class file
  3. {
  4. private:
  5.     class impl;
  6.     shared_ptr<impl> pimpl_;
  7. public:
  8.     file(char const * name, char const * mode);
  9.     // compiler generated members are fine and useful
  10.     void read(void * data, size_t size);
  11. };
  12. // file.cpp:
  13. #include "file.hpp"
  14. class file::impl
  15. {
  16. private:
  17.     impl(impl const >);
  18.     impl > operator=(impl const >);
  19.     // private data
  20. public:
  21.     impl(char const * name, char const * mode) { ... }
  22.     ~impl() { ... }
  23.     void read(void * data, size_t size) { ... }
  24. };
  25. file::file(char const * name, char const * mode): pimpl_(new impl(name, mode))
  26. {
  27. }
  28. void file::read(void * data, size_t size)
  29. {
  30.     pimpl_->read(data, size);
  31. }
复制代码
当然c++技巧太多,所以导致很多东西必须深入了解才能正确使用,也正因为如此,很多事实都应验了Linus Torvalds的话,不过又有谁会因为这些原因放弃c++呢? 至少我不会,不过我更喜欢C。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-30 18:45 , Processed in 0.015717 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表