Должен предоставить деструктор в PIMPL - PullRequest
5 голосов
/ 23 декабря 2011
// main_pimpl_sample.cpp
#include "pimpl_sample.hpp"

using namespace std;

int main()
{
  pimpl_sample p;

  return 0;
}

// pimpl_sample.cpp 

#include "pimpl_sample.hpp"

struct pimpl_sample::impl {
};

pimpl_sample::pimpl_sample()
  : pimpl_(new impl) {
}

// pimpl_sample::~pimpl_sample()
// cause problem if missed
// {}


// pimpl_sample.hpp

#if !defined (PIMPL_SAMPLE)
#define PIMPL_SAMPLE

#include <boost/scoped_ptr.hpp>

class pimpl_sample {
  struct impl;
  boost::scoped_ptr<impl> pimpl_;

public:
  pimpl_sample();
  //~pimpl_sample(); cause problem if missed
  void do_something();
};

#endif


~/Documents/C++/boost $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

~/Documents/C++/boost $ g++ -o main_pimpl_sample main_pimpl_sample.cpp pimpl_sample.cpp pimpl_sample.hpp
In file included from /usr/include/boost/smart_ptr/scoped_ptr.hpp:15:0,
                 from /usr/include/boost/scoped_ptr.hpp:14,
                 from pimpl_sample.hpp:6,
                 from main_pimpl_sample.cpp:2:
/usr/include/boost/checked_delete.hpp: In function ‘void boost::checked_delete(T*) [with T = pimpl_sample::impl]’:
/usr/include/boost/smart_ptr/scoped_ptr.hpp:80:9:   instantiated from ‘boost::scoped_ptr<T>::~scoped_ptr() [with T = pimpl_sample::impl]’
pimpl_sample.hpp:8:20:   instantiated from here
/usr/include/boost/checked_delete.hpp:32:58: error: invalid application of ‘sizeof’ to incomplete type ‘pimpl_sample::impl’ 
/usr/include/boost/checked_delete.hpp:32:58: error: creating array with negative size (‘-0x00000000000000001’)

Решение вышеуказанной ошибки компиляции состоит в том, чтобы вручную предоставить деструктор.Указанная причина заключается в следующем:

вы все равно должны помнить, чтобы определить деструктор вручную;причина в том, что в то время, когда компилятор генерирует неявный деструктор, тип impl является неполным, поэтому его деструктор не называется.

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

Спасибо

1 Ответ

7 голосов
/ 23 декабря 2011

TL; DR Объявите явный деструктор и внедрите его в модуль кода (не в заголовочный файл).

Если вы не создадитедеструктор, затем компилятор создает пустой автоматический деструктор в каждом модуле перевода, который пытается уничтожить объект этого класса.Вы бы получили эквивалентное поведение, если бы вы определили пустой встроенный деструктор в заголовке класса.

Это вызывает ошибку, потому что деструктор также отвечает за вызов деструкторов всех полей класса, которые - по порядку - нужнысоздание шаблона метода boost::scoped_ptr<impl>::~scoped_ptr();.Этот шаблон, в свою очередь, не может быть создан тогда, потому что он пытается удалить объект типа impl, который только объявлен в этой области только вперед (и вам нужно полное определение, чтобы знать, как удалить этот объект.


OTOH, если вы объявляете не встроенный конструктор в заголовке, его код генерируется только в pimpl_sample.cpp, где также содержится определение impl, поэтому деструктор scoped_ptr может быть успешно создан.

Другие единицы перевода затем вызывают только деструктор pimpl_sample как внешний метод, поэтому им не нужно генерировать его и создавать экземпляр деструктора scoped_ptr самостоятельно.

...