2012-03-30 55 views
0

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

我需要它来实现的,不能轻易复制和破坏对象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的情景通常用于:构造函数和对象的析构函数,其指针共享被调用一次。

但是在我的情况下,我宁愿避免在堆上分配对象。我需要一个类似std::shared_ptrshared_object类,以便我的类的非复制构造函数和destroy函数(在上例中)只被调用一次。

这样的事情是否存在?

+0

@NiklasB。析构函数需要做一些引用计数。 'shared_ptr'已经拥有所有内置的逻辑。 – 2012-03-30 01:44:36

+0

@R。马蒂尼奥:谢谢,我也意识到这一点。再看一眼代码永远不会受到伤害(: – 2012-03-30 01:46:31

+0

)如果你不打算在堆上维护引用计数,你打算如何维护引用计数? – 2012-03-30 01:50:43

回答

1

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

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


之所以这么说,使用std::shared_ptrstd::unique_ptr或助推变种可能会快写,更容易维护。如果动态分配和引用计数永远是瓶颈(我怀疑它会是什么,但是我们不能一概而论),您可以花时间使用自定义引用链接版本。

0

您可以将自己的删除器提供给std :: shared_ptr,该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); 
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(); 
    } 
}; 

一个双向链表。列表的最后一个成员,因此最后的重复调用会被销毁。不需要堆分配。

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

+0

缺少'operator =',在拷贝构造函数中修改'const'对象中的成员等。 – 2012-03-30 05:03:05

+0

@AndréCaron:谢谢,不打算成为成品。只是一个快速的涂鸦来传达建筑。 const_cast可以用来修改next和prev,而operator =的实现很简单。 – 2012-03-30 06:35:43

+0

更习惯的方法是将'next'和'prev'成员声明为'mutable'而不是使用'const_cast <>()',但是我的观点是你应该提到它在帖子中不完整的事实。 – 2012-03-30 14:11:56