C ++:对象的引用计数器

时间:2012-03-30 01:39:53

标签: c++ shared-ptr raii

我需要一个未在堆上分配的对象的引用计数器。

我需要它来对无法轻易复制和销毁的对象实现RAII机制:

class File
{
private:
    int fd;
public:
    File( const std::string &path ) ... // opening file
    destroy( );                         // actually closing file

    File( const File &f ) ...           // just copying the fd
    ~File( );                           // doing nothing
}

对于这样的场景,通常使用std::shared_ptr:共享指针的对象的构造函数和析构函数只调用一次。

但是,在我的情况下,我宁愿避免在堆上分配对象。我需要一个shared_object类来完成与std::shared_ptr类似的工作,这样我的类'非复制构造函数和destroy函数(在上面的例子中)只被调用一次

这样的事情是否存在?

3 个答案:

答案 0 :(得分:1)

如果您想在动态存储中分配 nothing (“在堆上”)时有共享指针行为,可以查看various smart pointer implementation strategies。在Modern C++ Design中,作者在“智能指针”一章中讨论了许多这些策略,即freely (and legally) available online

您感兴趣的技术是引用链接。使用此技术,智能指针对象在双向双向链表中链接在一起,而不是指向动态分配的引用计数器。


所有这一切,使用std::shared_ptrstd::unique_ptr或其Boost变体可能会更快写入并且更易于维护。如果动态分配和引用计数一直是瓶颈(我怀疑它会是,但是我们不能太匆忙地概括),你总是可以花时间使用自定义引用链接版本。

答案 1 :(得分:0)

您可以将自己的删除器提供给std :: shared_ptr,它将调用您的自定义销毁函数而不是删除。

class File
{
private:
    int fd;
public:
    static void destroyThis(File* f){f->destroy();}
    File( const std::string &path ) ... // opening file
    void destroy( );                         // actually closing file

    File( const File &f ) ...           // You probably don't need this anymore.
    ~File( );                           // doing nothing
};

File fileObj("path");
std::shared_ptr<File> pf(&fileObj,std::bind(&File::destroyThis,std::placeholders::_1));
std::shared_ptr<File> pf2(pf);

答案 2 :(得分:0)

我相信以下架构符合您的要求:

// pseudo-code
class File
{
private:
    int fd;
    File* prev;
    File* next;
public:
    File(const std::string &path) :
        fd(open(path)),
        prev(0),
        next(0)
    {}

    void destroy()
    {
        close(fd);
    }

    File( const File &f )
         fd(f.fd),
         prev(&f),
         next(f.next)
    {
         if (next)
             next->prev = this;

         f.next = this;
    }


    ~File()
    {
         if (prev)
            prev->next = next;

         if (next)
            next->prev = prev;

         if ((!prev) && (!next))
            destroy();
    }
};

在重复的File实例之间维护双向链表。列表的最后一个成员,因此最后一次重复调用destroy。无需分配堆。

(显然这不是线程安全的。您可以使用互斥锁进行保护,也可以使用无锁方法来维护列表。)