С++: 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 на нем в своем деструкторе. Вероятно, вы также должны реализовать или отключить конструктор копирования и оператор присваивания.