Удаление указателя на неполный тип и умных указателей - PullRequest
19 голосов
/ 09 апреля 2011

При попытке использовать auto_ptr с типом, который был объявлен с предварительным объявлением, например:

class A;
...
std::auto_ptr<A> a;

деструктор A не вызывается (очевидно, потому что auto_ptrвнутренне delete s базовый указатель и деструктор для неполного типа не могут быть вызваны).

Однако тот же код работает нормально, и деструктор вызывается при использовании std::shared_ptr вместо std::auto_ptr.Как это можно объяснить?

1 Ответ

35 голосов
/ 09 апреля 2011

A shared_ptr может быть объявлено с неполным типом, да.Тип не обязательно должен быть завершен до тех пор, пока вы не инициализируете или не сбросите его.

Когда вы инициализируете или сбрасываете shared_ptr для указания на новый объект, он создает «удалитель», который можно использовать для уничтожения объекта.объект.Например, рассмотрим следующее:

// somewhere where A is incomplete:
std::shared_ptr<class A> p;

// define A
class A { /* ... */ };

p.reset(new A());

Когда вы вызываете reset, A завершено, потому что вы создаете его экземпляр с использованием new.Функция reset создает и сохраняет внутреннее средство удаления, которое будет использоваться для уничтожения объекта с использованием delete.Поскольку A здесь завершено, то delete будет делать правильные вещи.

Делая это, shared_ptr не требует, чтобы A был завершен, когда объявлено shared_ptr<A>;требуется только, чтобы A был завершен, когда вызывается конструктор shared_ptr, который принимает необработанный указатель, или когда вы вызываете reset с необработанным указателем.

Обратите внимание, что если A является не завершенным, когда вы делаете одну из этих двух вещей, shared_ptr не будет делать правильные вещи, и поведение не определено (это объясняется в документация для boost::shared_ptr, которая, вероятно, является лучшим ресурсом для обучения правильному использованию shared_ptr, независимо от того, какую версию shared_ptr вы используете (Boost, TR1, C ++ 0x и т. Д..)).

Однако, если вы всегда следуете лучшим рекомендациям по использованию shared_ptr, особенно если вы всегда инициализируете и сбрасываете shared_ptr напрямую с указателем, полученным в результате вызова new - вам не придется беспокоиться о нарушении этого правила.

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

auto_ptrunique_ptr тоже) разработаны без лишних затрат: операции с ним должны быть такими же эффективными, как использование тупого указателя.Таким образом, auto_ptr не имеет этой функциональности.

...