まず者がコードの最小量で問題を再現してみましょう:
#include <memory>
class SomeClass;
int main()
{
std::unique_ptr<SomeClass> ptr;
}
エラー:
In file included from /opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/memory:81:0,
from <source>:1:
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = SomeClass]':
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:236:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = SomeClass; _Dp = std::default_delete<SomeClass>]'
<source>:7:30: required from here
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'SomeClass'
static_assert(sizeof(_Tp)>0,
^
Compiler exited with result code 1
ここに同じ問題(それは、継承を行うには何もないことを証明するために):
#include <memory>
class SomeClass;
class NotDerived
{
// ~NotDerived(); //defined in cpp
std::unique_ptr<SomeClass> ptr;
};
int main(){
NotDerived d;
}
エラー:
In file included from /opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/memory:81:0,
from <source>:1:
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = SomeClass]':
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:236:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = SomeClass; _Dp = std::default_delete<SomeClass>]'
<source>:5:7: required from here
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'SomeClass'
static_assert(sizeof(_Tp)>0,
^
Compiler exited with result code 1
は、今度は、unique_ptrを本当に何であるかを覚えてみましょう:ポインタの
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
そしてdefault_delete ...
Calls delete
on ptr
とdelete
(SomeClass
に)Someclass
を破壊したいので、それだろうあなたがまだ宣言していないものをSomeClass::~SomeClass
に電話する必要があります。したがって、エラー。
これはなぜ関連していますか?
コードでは、Derived
のデストラクタを宣言しないと、デストラクタをptr
と呼ぶデフォルトのものが生成されます。
この時点で、コンパイラは完全な定義をSomeClass
にする必要があります。そのため、コンパイラは破壊方法を知っています。
Derivedでデストラクタを宣言すると、この問題はDerived::~Derived
のimlementationに引き継がれます。
なぜ[Rule of zero](http://en.cppreference.com/w/cpp/language/rule_of_three)を使用しないのですか? –
@πάνταῥεcompilerコンパイラで定義されたコンストラクタ/デストラクタは暗黙的にインラインであり、スマートポインタに渡された型をヘッダで完全に知る必要があるため(前方宣言では不十分です)。 – Resurrection
本当に良い質問です。ありがとう! – Yola