С++: auto_ptr + форвардная декларация?

У меня есть класс вроде этого:

class Inner;

class Cont
{
public:
    Cont();
    virtual ~Cont();
private:
    Inner* m_inner;
};

в .cpp, конструктор создает экземпляр Inner с new и деструктор delete it. Это работает очень хорошо.
Теперь я хочу изменить этот код, чтобы использовать auto_ptr, поэтому пишу:

class Inner;

class Cont
{
public:
    Cont();
    virtual ~Cont();
private:
    std::auto_ptr<Inner> m_inner;
};

Теперь конструктор инициализировал auto_ptr, а деструктор ничего не делает.

Но это не сработает. проблема возникает, когда я создаю этот класс. Я получаю это предупреждение:

предупреждение C4150: удаление указателя на неполный тип "Внутренний"; нет деструктор называется

Ну, это, очевидно, очень плохо, и я понимаю, почему это происходит. Компилятор не знает о d'tor Inner при создании шаблона auto_ptr<Inner>

Итак, мой вопрос: есть ли способ использовать auto_ptr с форвардным объявлением, как это было в версии, использующей только простые указатели?
Для #include каждого класса я объявляю указатель на огромную стычку, а иногда просто невозможно. Как обычно эта проблема обрабатывается?

Ответ 1

Вам нужно включить заголовок, определяющий class Inner в файл, в котором находится реализация Cont::~Cont(). Таким образом, у вас все еще есть декларация в заголовке, определяющая class Cont, и компилятор видит определение class Inner и может вызывать деструктор.

//Cont.h
class Inner; // is defined in Inner.h
class Cont 
{ 
    virtual ~Cont(); 
    std::auto_ptr<Inner> m_inner;
};

// Cont.cpp
#include <Cont.h>
#include <Inner.h>

Cont::~Cont()
{
}

Ответ 2

Оказывается, проблема возникает только тогда, когда я делаю c'tor inline. Если я положил c'tor в cpp, после отклонения Inner все ок.

Ответ 3

Вместо этого вы можете использовать boost:: shared_ptr(). Он не имеет практических недостатков, а не производительности, и гораздо более дружелюбен к декларации вперед:

boost::shared_ptr<class NeverHeardNameBefore> ptr;

в порядке, без дополнительных деклараций выше.

shared_ptr делает больше, чем auto_ptr, например подсчет ссылок, но он не должен навредить, если он вам не нужен.

Ответ 4

Кажется, это смешно, но я решил ту же проблему, добавив #include <memory> в файл Cont.h.

Ответ 5

Форвардное объявление в заголовке одобрено, если вы реализуете деструктор в файле cont.cpp и включаете inner.h, как указывали другие.

Проблема может заключаться в использовании Cont. В каждом cpp, который использует (и уничтожает) Cont, вы должны включить cont.h AND inner.h. Это решило проблему в моем случае.

Ответ 6

Этот вопрос (удаление объекта с помощью частного деструктора) и этот вопрос (как написать незавершенный шаблон) может помочь вам.

Ответ 7

Вы технически не должны создавать стандартные шаблоны библиотек с неполными типами, хотя я не знаю, где реализация не будет работать. На практике ответ Sharptooth я также рекомендую.

На самом деле не было ничего плохого в использовании открытого указателя для вашего указателя impl, если вы вызываете delete на нем в своем деструкторе. Вероятно, вы также должны реализовать или отключить конструктор копирования и оператор присваивания.