2012-03-30 3 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 обычно используются: конструктор и деструктор объекта, указатель является общим только один раз.

В моем случае, однако, я бы предпочел избежать выделения объекта в куче. Мне нужен класс shared_object, который выполняет задание, подобное std::shared_ptr, так что мой класс 'non-copy-constructor и destroy (в приведенном выше примере) вызываются только один раз.

Есть ли что-нибудь подобное?

+0

@NiklasB. деструктор должен выполнить некоторый подсчет ссылок. 'shared_ptr' уже имеет всю встроенную логику. –

+0

@R. Martinho: Спасибо, только осознал это тоже. Второй взгляд на код никогда не повредит (: –

+0

Где вы планируете поддерживать счетчик ссылок, если не в куче? –

ответ

1

Если вы хотите иметь поведение общего указателя при распределении ничего в динамическом хранилище («на куче»), вы можете посмотреть various smart pointer implementation strategies. В Modern C++ Design автор обсуждает многие из этих стратегий в главе «Умные указатели», которая является freely (and legally) available online.

Техника, которая вас интересует, это ссылка link. Используя этот метод, объекты интеллектуального указателя связаны друг с другом в двунаправленном двусвязном списке вместо указания на динамически распределенный счетчик ссылок.


Все, что было сказано, с помощью std::shared_ptr, std::unique_ptr или их варианты Повышения, вероятно, будет гораздо быстрее писать и проще в обслуживании. Если динамическое распределение и счетчик ссылок всегда являются узким местом (я сомневаюсь, что это произойдет, но тогда мы не можем слишком быстро обобщить), вы всегда можете воспользоваться временем, чтобы вместо этого использовать специальную ссылку для ссылок.

0

Вы можете предоставить свой собственный deleter в 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' в конструкторе копирования и т. Д. –

+0

@ AndréCaron: Спасибо, не предназначен для конечного продукта. Просто быстрый текст, чтобы передать архитектуру. const_cast может использоваться для модификации next и prev, а operator = реализация проста. –

+0

Более идиоматичным способом является объявление членов 'next' и' prev' как 'mutable', а не использование' const_cast <>() ', но я хотел сказать, что вы должны упомянуть о том, что он неполный в сообщении. –

Смежные вопросы