Jack 发表于 2011-3-17 00:34:46

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]
查看完整版本: boost.enable_shared_from_this和boost.shared_ptr的使用