my_*_*ion 15 c++ language-lawyer c++11
我已经在这里和这里检查了问题,但仍然无法弄清楚出了什么问题.
这是调用代码:
#include "lib.h"
using namespace lib;
int
main(const int argc, const char *argv[])
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是lib代码:
#ifndef lib_h
#define lib_h
#include <string>
#include <vector>
#include <memory>
namespace lib
{
class Foo_impl;
class Foo
{
public:
Foo();
~Foo();
private:
Foo(const Foo&);
Foo& operator=(const Foo&);
std::unique_ptr<Foo_impl> m_impl = nullptr;
friend class Foo_impl;
};
} // namespace
#endif
Run Code Online (Sandbox Code Playgroud)
clang ++给了我这个错误:
将'sizeof'无效应用于不完整类型'lib :: Foo_impl'
注意:在成员函数'std :: default_delete :: operator()'的实例化中请求
你可以看到我已经特别声明了Foo析构函数.我还缺少什么?
Nia*_*all 10
Foo_impl
必须在实例化之前完成实现std::unique_ptr<Foo_impl> m_impl = nullptr
.
保留声明的类型(但未初始化)将修复错误(std::unique_ptr<Foo_impl> m_impl;
),然后您需要在代码中稍后初始化它.
您看到的错误来自用于测试此技术的技术的实现; 不完整的类型.基本上,sizeof
将导致仅向前声明的类型的错误(即在代码/编译中的该点处使用时缺少定义).
这里有一个可能的解决方案;
class Foo_impl;
class Foo
{
// redacted
public:
Foo();
~Foo();
private:
Foo(const Foo&);
Foo& operator=(const Foo&);
std::unique_ptr<Foo_impl> m_impl;// = nullptr;
};
class Foo_impl {
// ...
};
Foo::Foo() : m_impl(nullptr)
{
}
Run Code Online (Sandbox Code Playgroud)
为什么需要完整的类型?
实例化通过= nullptr
使用复制初始化并要求声明(for unique_ptr<Foo_impl>
)构造函数和析构函数.析构函数需要删除函数unique_ptr
,默认情况下,调用delete
指针,Foo_impl
因此它需要析构函数Foo_impl
,并且析构函数Foo_impl
不是以不完整类型声明(编译器不知道它是什么样的).请参阅霍华德对此的回答.
这里的关键是调用delete
一个不完整的类型导致未定义的行为(第5.3.5/5节),因此在实现中明确检查unique_ptr
.
对于这种情况的另一种替代方案可以是使用如下的直接初始化 ;
std::unique_ptr<Foo_impl> m_impl { nullptr };
Run Code Online (Sandbox Code Playgroud)
关于非静态数据成员初始化器(NSDMI)似乎存在一些争论,以及这是否是需要成员定义存在的上下文,至少对于clang(可能还有gcc),这似乎是这样的上下文.
该声明:
std::unique_ptr<Foo_impl> m_impl = nullptr;
Run Code Online (Sandbox Code Playgroud)
调用复制初始化.它具有与以下相同的语义:
std::unique_ptr<Foo_impl> m_impl = std::unique_ptr<Foo_impl>(nullptr);
Run Code Online (Sandbox Code Playgroud)
即它构造一个临时的prvalue.必须破坏此临时prvalue.而析构函数需要查看完整类型Foo_impl
.即使省略了prvalue和move构造,编译器也必须"好像".
您可以改为使用直接初始化,此时unique_ptr
将不再需要析构函数:
std::unique_ptr<Foo_impl> m_impl{nullptr};
Run Code Online (Sandbox Code Playgroud)
更新
Casey指出,~unique_ptr()
即使是直接初始化形式,gcc-4.9目前也会实例化.但是在我的测试中,clang没有.我不知道其他编译器可能会做什么.我认为 clang在这方面是合规的,至少在最新的核心缺陷报告中考虑到了.
归档时间: |
|
查看次数: |
2900 次 |
最近记录: |