Почему shared_ptr не имеет виртуального дескриптора?(и как я могу обойти это?) - PullRequest
0 голосов
/ 27 сентября 2010

Я хотел создать специальную версию shared_ptr, которая выполняла бы определенные операции, когда она была создана или уничтожена, но мои планы, похоже, были сорваны осознанием того, что деструктор shared_ptr не виртуален, то есть когда я переопределите его, мои указатели никогда не будут очищены, когда последний экземпляр из них будет уничтожен.

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

Edit:

Причина, по которой я этого хочу, заключается в том, что я хочу использовать некоторые классы в качестве объектов пользовательских данных в lua, и я хочу, чтобы каждый из моих объектов, которые я использую таким образом, имел уникальную таблицу fenv, которая будет очищена, когда все ссылки на объект были удалены. Я планирую использовать адрес указателя при вводе ключа в таблицу, содержащую таблицу fenv.

Допустим, у меня есть виджет, который может иметь другие виджеты в качестве детей. Я создаю два виджета в Lua, затем устанавливаю один как дочерний для другого и удаляю все ссылки lua на дочерний виджет (факт, что это дочерний элемент, обрабатывается в C ++). GC теперь может работать в любое время и удалить ребенка. Я не обязательно хочу, чтобы у ребенка был запущен деструктор, поэтому я хочу сделать его shared_ptr. Таким образом, объекты C ++ могут все еще использовать его после того, как Lua очистил его. Если я назначил значения или функции для этого fenv, я все еще хочу иметь доступ к ним. Только после удаления окончательной ссылки на мой дочерний виджет я хочу полностью удалить таблицу fenv.

Ответы [ 4 ]

8 голосов
/ 27 сентября 2010

В него уже встроена эта способность без необходимости позволять людям совершать опасные вещи, такие как производные от нее:

#include <boost/shared_ptr.hpp>
#include <iostream>

/*
 * Done as a function for simplicity.
 * But this can be done in so many ways
 */
void MyCleanup(int* x)
{
    std::cout << "DONE\n";
    delete x;
}

int main()
{
    boost::shared_ptr<int>  x(new int(5), MyCleanup);

}

Проблема с производным:
Просто с моей головы.*

class X: public shared_ptr<int> { /* STUFF. With a special destructor. */ };

int main()
{
    /* what happens now? Similar to slicing but not quite */
    X                data1(new int(5));
    shared_ptr<int>  data2;
    shared_ptr<int>  data3(data);

    data2 = data1;
}
4 голосов
/ 27 сентября 2010

Просто сделайте объект-обертку; намного легче. Вы можете иметь объект-оболочку с экземпляром shared_ptr внутри себя, и все же использовать адрес выделения внутреннего объекта в качестве индекса. Это кажется намного лучше, чем дурачиться с деривацией или пользовательскими процедурами очистки, если я что-то упустил.

Например:

class CWrapsLuaObject
{
    CWrapsLuaObject( LuaObject* pObject )
    { [assign internal ptr, do mapping, etc.] }

    shared_ptr< LuaObject > m_spObject;

    [...]
};

shared_ptr< CWrapsLuaObject > spInstance( new CWrapsLuaObject( pObject ) );

Мне не хватает, почему это не будет самым простым решением (ничего не забирая у других предлагаемых решений, которые также могут работать)?

1 голос
/ 27 сентября 2010

Вы можете предоставить пользовательский объект удаления, который будет использоваться с shared_ptr. Если вы пытаетесь вставить дополнительную информацию в shared_ptr, возможно, вам лучше поместить ее в объект удаления. Мне не очень чисто, но это работает.

class ExtraThingToDestroy
{
  public:
   ~ExtraThingToDestroy() { std::cout<<"Destroying the extra thing"<<std::endl; }
};

template<typename T>
class CustomDestructor
{
  public:
    CustomDestructor( ExtraThingToDestroy * v ) : v_(v) {}
    void operator()( T* t ) { delete t; delete v_; }
    ExtraThingToDestroy * v_;
};

main()
{
   shared_ptr<int> ptr( new int, MyExtraDestructor<int>( new ExtraThingToDestroy ) );
   shared_ptr<int> ptr2 = ptr;
   //Now when ptr and all its copies get destroyed, 
   // the ExtraThingToDestroy will get deleted along with the int.
} 
0 голосов
/ 27 сентября 2010

если вы наследуете класс your_shared_ptr из shared_ptr и переопределяете деструктор, ваш деструктор должен вызываться в коде, подобном следующему:

{
  your_shared_ptr<int> x(new int);
}

Если вы используете его следующим образом, вместо:

{
  shared_ptr<int>* ptrptr = new your_shared_ptr<int>(new int);
}

тогда не будет, но тебе это действительно нужно?

Или я что-то неправильно понимаю?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...