Рассмотрим этот код с очевидной ошибкой компиляции: (1)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
Использование unique_ptr
не поможет: (2)
struct A;
struct B {
B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};
Тогда (к моему большому удивлению) я узнал, что этот будет компилировать: (3)
struct A;
struct B {
B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**
Затем я проверил, помогает ли это с new
- nope: (4)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
Я полагал, что это имеет какое-то отношение к template
и на самом деле: wrapping new
внутри template
делает компиляцию: (5)
template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
B() { my_new<A>(); }
};
struct A {};
И только ради полноты, удаление определения A
снова вызывает ошибку: (6)
template <typename T>
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
B() { my_new<A>(); }
};
// do note: definition of A removed
Что здесь происходит? Насколько я понял, компилятор должен знать размер/определение A
, чтобы выделить его, просто объявив его, недостаточно. Кроме того, я полагал, что определение должно предшествовать распределению.
Это кажется правильным, если непосредственно использовать new
(1,4). Но когда new
завернуто, очевидно, что я ошибаюсь (2,3,5,6).
Возможные объяснения, которые я нашел до сих пор:
- Проверка завершенных типов задерживается до тех пор, пока не произойдет создание
template
. Я думаю, что это правильно, но в моем случае прямое использованиеnew A()
и вызовmy_new<A>()
происходят практически в одной и той же позиции. Так что это не может быть причиной. Правильно? - Использование неполных типов в качестве
template
Аргументы могут быть undefined. Это правда? Даже при включении всех предупреждений компилятор не будет жаловаться. Кроме того, сравнение 5 и 6, по-видимому, предполагает, что компилятор достаточно умен, чтобы понять, что определение ниже (таким образом, фактически завершая тип).
Почему 4 считается некорректным, в то время как 5 компиляций (или 5 просто ложно компилируют поведение undefined [но затем 3 также должны быть ошибочными, правильно?])?
btw: проверено с помощью clang++ - 3.5.0 и g++ - 4.9.2