boost.enable_shared_from_this结合boost.shared_ptr似乎非常完美, 其实不然,
使用它还是需要注意很多地方, 如果不注意, 那也将会导致致命性的错误.
1. 首先enable_shared_from_this不能在构造函数中使用.
show code:- class tester
- : public boost::enable_shared_from_this<tester>
- {
- public:
- tester()
- {
- boost::shared_ptr<tester> sp = shared_from_this(); // 错误的使用!!!
- }
- };
复制代码 2. 析构函数执行时, 析构函数内部不能调用shared_from_this(); 并且其它线程也不能再使用shared_from_this();
show code- class tester
- : public boost::enable_shared_from_this<tester>
- {
- public:
- tester()
- {
- // boost::shared_ptr<tester> sp = shared_from_this(); // 错误的使用!!!
- }
- ~tester()
- {
- Sleep(0xFFFFFFFF); // 析构一直不退出.
- }
- void start()
- {
- boost::shared_ptr<tester> ts;
- boost::thread t1(boost::bind(&tester::operation, this, boost::ref(ts)));
- }
- void operation(boost::shared_ptr<tester>& sp)
- {
- for (;;)
- {
- // 线程中使用shared_from_this()!!!
- // 当这个对象的生命期到了结束时(还未结束),
- // 执行析构函数时, 这里将导致错误!!!
- // 也就是说, 只要对象执行到析构函数, 无论如何
- // 都不能再调用这个对象的shared_from_this!
- sp = shared_from_this();
- Sleep(100);
- }
- }
- };
- int main(int argc, char* argv[])
- {
- boost::shared_ptr<tester> sp(new tester);
- sp->start();
- return 0;
- }
复制代码 还有好几种情况, 有空全部总结下, 并把原因也列出来.
总之如果实在难以把握的话, 又要把在中间this一样的智能指针的时候, 还是使用boost.intrusive_ptr吧, 还有就是COM指针也可以boost.intrusive_ptr来包装,或者也可以使用shared_ptr直接如下:
show code:- template <class _RawComPtr>
- boost::shared_ptr<_RawComPtr> make_shared_from_COM(_RawComPtr * p)
- {
- p->AddRef();
- boost::shared_ptr<_RawComPtr> pw(p, boost::mem_fn(&_RawComPtr::Release));
- return pw;
- }
复制代码 这样写成一个模板,似乎也是很不错的做法。类似的包装像FILE*这样的也非常方便,如:
show code:- boost::shared_ptr<FILE> spfile(fopen("c:\\test.dat", "w+b"), fclose);
- // 写时可以:
- fwrite(buf, n, n, >(*spfile));
- // 或:
- fwrite(buf, n, n, spfile.get());
- // 这样就会当智能指针撤消时,自动fclose掉这个文件。当然也可以写删除器来完成。不过最简单就简单些吧。
复制代码 另外,更值得推荐的就是使用它来做"Pimpl",这种做法在许多的质量比较高的开源库里广泛使用,如libtorrent等...类似的代码像:
show code:- // file.hpp:
- class file
- {
- private:
- class impl;
- shared_ptr<impl> pimpl_;
- public:
- file(char const * name, char const * mode);
- // compiler generated members are fine and useful
- void read(void * data, size_t size);
- };
- // file.cpp:
- #include "file.hpp"
- class file::impl
- {
- private:
- impl(impl const >);
- impl > operator=(impl const >);
- // private data
- public:
- impl(char const * name, char const * mode) { ... }
- ~impl() { ... }
- void read(void * data, size_t size) { ... }
- };
- file::file(char const * name, char const * mode): pimpl_(new impl(name, mode))
- {
- }
- void file::read(void * data, size_t size)
- {
- pimpl_->read(data, size);
- }
复制代码 当然c++技巧太多,所以导致很多东西必须深入了解才能正确使用,也正因为如此,很多事实都应验了Linus Torvalds的话,不过又有谁会因为这些原因放弃c++呢? 至少我不会,不过我更喜欢C。 |