C ++: счетчик ссылок для объектов - PullRequest
0 голосов
/ 30 марта 2012

Мне нужен счетчик ссылок для объекта, не выделенного в куче.

Мне нужен его для реализации механизма 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 ]

1 голос
/ 30 марта 2012

Если вы хотите иметь поведение общего указателя при выделении ничего в динамическом хранилище («в куче»), вы можете посмотреть различные стратегии реализации интеллектуальных указателей Modern C ++ Design автор обсуждает многие из этих стратегий в главе «Умные указатели», которая свободно (и легально) доступна онлайн .

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


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

0 голосов
/ 30 марта 2012

Я полагаю, что следующая архитектура удовлетворяет вашим требованиям:

// 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 голосов
/ 30 марта 2012

Вы можете предоставить свой собственный удалитель для 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);
...