Подтвердить что ты не робот

Удаление указателя на неполный тип и интеллектуальные указатели

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

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

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

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

4b9b3361

Ответ 1

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

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

// 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 не будет делать правильные вещи, а поведение undefined (это объясняется в документация для boost::shared_ptr, которая, вероятно, является лучшим ресурсом для обучения правильному использованию shared_ptr, независимо от того, какую версию shared_ptr вы используете (Boost, TR1, С++ 0x и т.д.)).

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

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

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