Unique_ptr и форвардная декларация

Скажем, у меня есть два класса:

"foo.h"

#pragma once    
class Foo
{
public:
    Foo()
    {

    };

    ~Foo()
    {

    };
};

"хиджра"

#pragma once
#include <memory>

class Foo;

class A
{
public:
    A(){};
    ~A(){};

    std::unique_ptr<Foo> foo;
};

A содержит a unique_ptr of Foo. Я не хотел включать Foo в "A.h" , поэтому я просил объявить его. Просто объявив класс Foo в "A.h" , я получаю ошибку времени компиляции:

error C2027: use of undefined type 'Foo'
error C2338: can't delete an incomplete type  

Итак, я следил за этой статьей о том, как избежать этой ошибки, и переместил деструктор в свой собственный .cpp файл, где я также включаю Foo:

"a.cpp"

#include "A.h"

#include "Foo.h"

A::A()
{

}

A::~A()
{

}

После реализации деструктора A в "A.cpp" я могу скомпилировать программу, потому что класс Foo известен в "A.cpp" . Это кажется логичным, потому что unique_ptr нуждается в полном типе, чтобы назвать его деструктором. Но, к моему удивлению, после комментирования конструктора A (в "A.h" , а также "A.cpp" ), я получаю ту же ошибку. Как это возможно? Почему компилятор жалуется на невозможность вызвать Foo destructor, когда A не имеет конструктора?

EDIT: Я загрузил 4 файла, чтобы вы могли протестировать программу. Я использую MSVС++ Visual Studio 2013.

http://www.filedropper.com/test_61

Ответы

Ответ 1

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

[C++14: 12.6.2/10]: В конструкторе без делегирования потенциально вызывается деструктор для каждого потенциально сконструированного подобъекта типа класса (12.4). [Примечание. Это условие гарантирует, что деструкторы могут быть вызваны для полностью построенных под-объектов в случае возникновения исключения (15.2). -end note]

по теме:

Ответ 2

Невозможно, чтобы "A" не имел конструктора.

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