enable_shared_from_this使用

  • 如果T类型的一个对象obj的生命周期为:如果这个obj没有被其它对象(假设B)引用了,则析构。所以这个对象obj使用shared_ptr管理。但是一个问题是:B对象是obj中方法返回出来的,所以,在创建对象B的时候,就需要传obj的引用给他。为此引入enable_shared_from_this方便这个。

  • 如果T继承了enable_shared_from_this,那么该类拥有了shared_from_this()方法,如果obj是使用名为pt的shared_ptr管理的,调用shared_from_this()会返回和pt共享同一个obj的shared_ptr对象,如果obj没有没shared_ptr管理,调用该方法会出错。

  • 使用场景: 创建要给数据对象,该数据对象可以返回迭代器用于迭代它,所以数据对象只有当其上面的所有迭代器对象都销毁时,其才可以销毁。为此选择数据对象类型继承enable_shared_from_this,这样其在创建迭代器时可以通过shared_from_this()方法返回当前this的引用。如果数据对象最开始不是一个shared_ptr,则将会出错。

  • 参考:https://github.com/vesoft-inc/nebula/blob/master/src/kvstore/wal/FileBasedWal.cpp

class FileBasedWal final : public Wal
                         , public enable_shared_from_this<FileBasedWal> {

~FileBasedWal() {
    // FileBasedWal inherits from std::enable_shared_from_this, so at this
    // moment, there should have no other thread holding this WAL object
    // Close the last file
    closeCurrFile();
    LOG(INFO) << idStr_ << "~FileBasedWal, dir = " << dir_;
}

// FileBasedWal 对象直到上面的所有FileBasedWalIterator都释放后,其才会调用析构函数,
// 如果继承enable_shared_from_this,你在一个类方法中无法完成这一步: 返回一个FileBasedWalIterator,该FileBasedWalIterator的参数为FileBasedWal 的shared_ptr智能指针
std::unique_ptr<LogIterator> iterator(LogID firstLogId,
                                                         LogID lastLogId) {
    return std::make_unique<FileBasedWalIterator>(shared_from_this(), firstLogId, lastLogId);
}
};


class FileBasedWalIterator final : public LogIterator {
public:
    // The range is [startId, lastId]
    // if the lastId < 0, the wal_->lastId_ will be used
    FileBasedWalIterator(std::shared_ptr<FileBasedWal> wal,
                         LogID startId,
                         LogID lastId = -1);
;
    virtual ~FileBasedWalIterator();

    LogIterator& operator++() override;

    bool valid() const override;

    LogID logId() const override;

private:
    // Holds the Wal object, so that it will not be destroyed before the iterator
    std::shared_ptr<FileBasedWal> wal_;
};



int main() {
      std::unique_ptr<FileBasedWalIterator> iter1;
      std::unique_ptr<FileBasedWalIterator> iter2;
    {
         std::shared_ptr<FileBasedWal> wal(new FileBasedWal(....));
         iter1 = wal->iterator(...);
         iter2 = wal->iterator(...);
         // 作用域推出后,wal并不会被析构,因为iter对其进行了引用
    }
    iter其它操作
    iter1,iter2都析构后,wal才会析构
}