boost.enable_shared_from_this和boost.shared_ptr的使用
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。
页:
[1]