我在标题中有一些代码,看起来像这样:
#include <memory>
class Thing;
class MyClass
{
std::unique_ptr< Thing > my_thing;
};
如果我在一个不包括Thing类型定义的cpp中包含这个头,那么这不会在VS2010-SP1下编译:
1>C:\程序文件(x86)\微软
Visual Studio
10.0\VC\include\memory(2067):错误C2027:使用未定义的类型'Thing'
将std::unique_ptr替换为std::shared_ptr并进行编译。
所以,我猜是当前的VS2010 std::unique_ptr的实现需要完整的定义,它完全依赖于实现。
真的是这样吗?它的标准要求中是否有一些东西使得std::unique_ptr的实现不可能只使用前向声明?这感觉很奇怪,因为它应该只持有一个指向Thing的指针,不是吗?
看起来目前的答案并没有完全确定为什么默认构造函数(或析构函数)是问题,而在cpp中声明的空构造函数不是问题。
事情是这样的:
If outer class (i.e. MyClass) doesn't have constructor or destructor then compiler generates the default ones. The problem with this is that compiler essentially inserts the default empty constructor/destructor in the .hpp file. This means that the code for default contructor/destructor gets compiled along with host executable's binary, not along with your library's binaries. However this definitions can't really construct the partial classes. So when linker goes in your library's binary and tries to get constructor/destructor, it doesn't find any and you get error. If the constructor/destructor code was in your .cpp then your library binary has that available for linking.
这与使用unique_ptr或shared_ptr和其他答案似乎是旧vc++的unique_ptr实现中可能令人困惑的错误(vc++ 2015在我的机器上工作良好)。
所以这个故事的寓意是你的头文件需要保持不受任何构造函数/析构函数定义的影响。它只能包含他们的声明。例如,~MyClass()=default;在HPP行不通。如果允许编译器插入默认构造函数或析构函数,则会得到链接器错误。
另一个旁注:如果在cpp文件中有构造函数和析构函数后仍然出现这个错误,那么很可能是库没有正确编译。例如,有一次我在vc++中简单地将项目类型从控制台更改为库,我得到了这个错误,因为vc++没有添加_LIB预处理器符号,这产生了完全相同的错误消息。