我需要一个未在堆上分配的对象的引用计数器。
我需要它来对无法轻易复制和销毁的对象实现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
函数(在上面的例子中)只被调用一次
这样的事情是否存在?
答案 0 :(得分:1)
如果您想在动态存储中分配 nothing (“在堆上”)时有共享指针行为,可以查看various smart pointer implementation strategies。在Modern C++ Design中,作者在“智能指针”一章中讨论了许多这些策略,即freely (and legally) available online。
您感兴趣的技术是引用链接。使用此技术,智能指针对象在双向双向链表中链接在一起,而不是指向动态分配的引用计数器。
所有这一切,使用std::shared_ptr
,std::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。无需分配堆。
(显然这不是线程安全的。您可以使用互斥锁进行保护,也可以使用无锁方法来维护列表。)