2009-12-23 2 views
11

У меня есть класс, как это:C++: auto_ptr + форвардная декларация?

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: удаление указателя на неполный тип 'Внутренний'; нет деструктора называется

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

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

+0

Я использовал эту проблему, когда объявил пустой деструктор (или вообще не объявлял его) в файле заголовка класса Cont. Из вашего примера там вы, кажется, делаете это правильно, но просто хотели подчеркнуть эту проблему. – rui

+0

Древо объявлено в cpp, и я получаю предупреждение о создании экземпляра 'auto_ptr' внутри класса. – shoosh

ответ

12

Вам необходимо включить заголовок, определяющий 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() 
{ 
} 
+0

Я делаю это, но предупреждение указывает, что 'Inner' необходимо определить в строке экземпляра' auto_ptr' внутри класса. – shoosh

+1

Это очень странно. Это Visual C++? – sharptooth

+0

да, это MSVC2008 – shoosh

3

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

boost::shared_ptr<class NeverHeardNameBefore> ptr;

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

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

+0

Или 'boost :: scoped_ptr', который ближе, за исключением того, что он даже не пытается притворяться, что ваши экземпляры будут скопированы. Но тогда он все равно не отвечает на вопрос, как следует использовать их с неполными типами (я думаю, вам нужно определить деструктор, по истечении которого тип будет завершен). – UncleBens

0

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

+0

нет, не очень. – shoosh

0

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

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

4

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

1

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

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

3

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

Смежные вопросы