я прочитал Является ли std :: unique_ptr<T> Требуется знать полное определение Т? а также Переслать объявление с unique_ptr?, но мой вопрос более конкретный.
Следующие компиляции:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a;
};
Следующее не делает:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a{nullptr};
};
Ошибка
$ g++ -std=c++11 -c fwd_decl_u_ptr.cpp
In file included from /usr/include/c++/4.7/memory:86:0,
from fwd_decl_u_ptr.cpp:3:
/usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = A]’:
/usr/include/c++/4.7/bits/unique_ptr.h:173:4: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = A; _Dp = std::default_delete<A>]’
fwd_decl_u_ptr.cpp:9:33: required from here
/usr/include/c++/4.7/bits/unique_ptr.h:63:14: error: invalid application of ‘sizeof’ to incomplete type ‘A’
РЕДАКТИРОВАТЬ:
Насколько я понимаю, здесь происходит то, что инициализатор в классе подразумевает способность инициализировать unique_ptr<A>
уже в момент объявления AUser
, Так как тип unique_ptr<A>
на самом деле unique_ptr<A, default_delete<A>>
возможность инициализации подразумевает возможность инициализации default_delete<A>
, И для этого A
должен быть полностью определен.
Слабым звеном в этом рассуждении является предположение, что инициализатор в классе подразумевает возможность инициализации соответствующего члена данных в момент объявления класса! Это кажется интуитивно понятным, поскольку инициализатор является частью декларации. Но мне было бы удобнее, если бы я нашел что-то в стандарте, явно указав это. В противном случае я все еще могу думать о решениях для реализации, которые бы не требовали этого. Например, компилятор может просто взять выражение инициализатора и применить его только в конструкторах, где инициализация атрибута не была задана явно.
Итак, может ли кто-нибудь отослать меня к стандартному разделу / отрывку, который подразумевает необходимость полного определения A во втором случае? Я не нашел много о инициализаторах в классе в стандарте (только нашел, что их называют «скобки или равно-инициализаторы не статично
данные членов «), но с этим ничего не связано.
Во втором случае генерируется деструктор по умолчанию [неверный] в месте AUser
определение [/ Неправильно] (в этом случае это фактически делается после обработки всего кода). Так же, как определение конструктора внутри AUser
сделал бы.
Тем не менее, в любом случае вам нужно дать определение A
в том же модуле компиляции. Так может просто что-то подобное удовлетворит тебя?
#include <memory>
class A;
class AUser
{
std::unique_ptr<A> m_a;
AUser();
};class A
{
// ...
};AUser::AUser()
: m_a(nullptr)
{ }
Других решений пока нет …