С++:auto_ptr + форвардное объявление?
-
21-09-2019 - |
Вопрос
У меня есть такой класс:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
Inner* m_inner;
};
в .cpp конструктор создает экземпляр Inner
с new
и деструктор delete
сидеть.Это работает довольно хорошо.
Теперь я хочу изменить этот код, чтобы использовать auto_ptr
поэтому я пишу:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
std::auto_ptr<Inner> m_inner;
};
Теперь конструктор инициализировал auto_ptr
и деструктор ничего не делает.
Но это не работает.проблема, похоже, возникает, когда я создаю экземпляр этого класса.Я получаю это предупреждение:
предупреждение C4150:Удаление указателя на неполный тип «внутренний»;Ни один деструктор не называется
Ну это явно очень плохо и я понимаю почему так происходит. Составитель не знает о д'торе Inner
при создании экземпляра шаблона auto_ptr<Inner>
Итак, мой вопрос:Есть ли способ использовать auto_ptr
с предварительным объявлением, как я сделал в версии, в которой используются только простые указатели?
Того, чтобы #include
каждый класс, на который я объявляю указатель, представляет собой огромную проблему, а иногда и просто невозможную.Как обычно решается эта проблема?
Решение
Вам необходимо включить заголовок, определяющий 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()
{
}
Другие советы
Оказывается, проблема возникает только тогда, когда я делаю c'tor встроенным.Если я поставлю c'tor в cpp, после объявления Inner
все хорошо.
Вместо этого вы можете рассмотреть boost::shared_ptr().Он не имеет практических недостатков, а не производительности, и гораздо удобнее пересылать объявления:
boost::shared_ptr<class NeverHeardNameBefore> ptr;
все в порядке, без дополнительных объявлений выше.
Shared_ptr делает больше, чем auto_ptr, например, подсчитывает ссылки, но это не должно навредить, если вам это не нужно.
Это кажется смешным, но я решил ту же проблему, добавив #include <memory>
в файл Cont.h.
Предварительное объявление в заголовке допустимо, если вы реализуете деструктор в файле cont.cpp и включаете внутренний.h, как указывали другие.
Проблема может быть в использовании Cont.В каждый cpp, который использует (и уничтожает) Cont, вы должны включить cont.h И внутренний.h.Это решило проблему в моем случае.
Этот вопрос (удаление объекта с помощью частного деструктора) и этот вопрос (как написать шаблон iscomplete) может вам помочь.
Технически не предполагается создавать экземпляры шаблонов стандартной библиотеки с неполными типами, хотя я не знаю ни одной реализации, в которой это не работало бы.На практике я бы также порекомендовал ответ Sharptooth.
На самом деле нет ничего плохого в использовании голого указателя в качестве указателя реализации, если вы вызываете delete для него в своем деструкторе.Вероятно, вам также следует реализовать или отключить конструктор копирования и оператор присваивания.