MSVC:
error C2338: can’t delete an incomplete type
warning C4150: deletion of pointer to incomplete type ‘base’;
Clang:
error : invalid application of 'sizeof' to an incomplete type 'base'
static_assert(0 < sizeof (_Ty),
^~~~~~~~~~~~
note: in instantiation of member function 'std::default_delete<base>::operator()' requested here
this->get_deleter()(get());
^
./main.h(6,8) : note: in instantiation of member function 'std::unique_ptr<base, std::default_delete<base> >::~unique_ptr' requested here
struct test
^
./main.h(5,8) : note: forward declaration of 'base'
struct base;
看到这里,还是要感谢下clang的输出,比较清楚地把问题的本质原因找出来了
Demo:
1 #pragma once
2
3 struct base
4 {
5 int x;
6 };
base.h
1 #pragma once
2
3 #include <memory>
4
5 struct base;
6 struct test
7 {
8 std::unique_ptr<base> base_;
9
10 void print_base() const;
11 };
test.h
1 #include "main.h"
2 #include "base.h"
3
4 #include <cstdio>
5
6 void
7 test::print_base() const
8 {
9 std::printf("%d\n", base_->x);
10 }
test.cpp
1 #include "test.h"
2
3 int main()
4 {
5 test t;
6 t.print_base();
7
8 return 0;
9 }
main.cpp
std::unique_ptr base_; 使用了前置声明的base
因为test类没有声明构造或者析构函数所以编译器生成了一个默认的构造和析构函数
If a class has no user-declared destructor, a destructor is implicitly declared as defaulted(8.4). An implicitly declared destructor is an inline public member of its class.
如果一个类没有用户声明的构造或者析构函数,析构函数会被隐式地声明为默认析构函数(8.4)。隐式声明的析构函数是其类的内联公有成员。
在编译时遇到test没有声明构造和析构就会默认生成,但是在这个位置还没有include base的头文件,展开模板就会报错
template <class _Ty, class _Dx = default_delete<_Ty>>
class unique_ptr;
template <class _Ty, class _Dx = default_delete<_Ty>>
class unique_ptr;
template <class _Ty>
struct default_delete { // default deleter for unique_ptr
constexpr default_delete() noexcept = default;
template <class _Ty2, enable_if_t<is_convertible_v<_Ty2*, _Ty*>, int> = 0>
default_delete(const default_delete<_Ty2>&) noexcept {}
void operator()(_Ty* _Ptr) const noexcept /* strengthened */ { // delete a pointer
static_assert(0 < sizeof(_Ty), "can't delete an incomplete type");
delete _Ptr;
}
};