首先阅读Herb's Sutters GotW关于C++ 11中pimpl的帖子:
我在理解GotW#101中提出的解决方案时遇到了一些麻烦.据我所知,在GotW#100中辛苦解决的所有问题都复仇了:
的pimpl成员是外的线的模板,并且定义并不在使用点可见(在class widget的类定义和隐式生成的特殊成员函数widget).也没有任何明确的实例化.这将导致链接期间未解决的外部错误.
widget::impl在实例化定义的点上仍然是不完整的(我认为它实际上根本没有pimpl<widget::impl>::~pimpl()被实例化,只是被引用).因此std::unique_ptr<widget::impl>::~unique_ptr()调用delete指向不完整类型的指针,如果widget::impl有一个非平凡的析构函数,则会产生未定义的行为.
请解释是什么迫使编译器在widget::impl完成的上下文中生成特殊成员.因为我看不出它是如何工作的.
如果GotW#101仍然需要widget::~widget()在实现文件中明确定义,哪里widget::impl完成,那么请解释"更健壮"的评论(@sehe在他的答案中引用).
我看的GotW#101的核心要求是,包装"消除样板的一些作品",这在我看来(基于该段的其余部分)来表示的widget::~widget()声明和定义.所以请不要依赖于你的答案,在GotW#101中,那已经消失了!
Herb,如果你停下来,请告诉我是否可以在这里剪切+粘贴解决方案代码以供参考.
我在"C++编程语言"第4版中学习了大括号分隔初始化器.>第2章:C++之旅:基础知识.
我引用下面的书.
=表格是传统的并且可以追溯到C,但是如果有疑问,请使用通用{} -list表单(第6.3.5.2节).如果不出意外,它可以帮助您避免丢失信息的转换(缩小转化次数;§10.5):
Run Code Online (Sandbox Code Playgroud)int i1 = 7.2; // i1 becomes 7 int i2 {7.2}; // error : floating-point to integer conversion int i3 = {7.2}; // error : floating-point to integer conversion (the = is redundant)
但是,我无法重现这些结果.
我有以下代码.
#include <iostream>
int main()
{
int i1 = 7.2;
int i2 {7.2};
int i3 = {7.2};
std::cout << i1 << "\n";
std::cout << i2 << "\n";
std::cout << i3 << "\n";
}
Run Code Online (Sandbox Code Playgroud)
当我编译并运行它时,我没有得到任何错误.我收到警告,std=c++11但没有错误.
$ g++ init.cpp
init.cpp: In function …Run Code Online (Sandbox Code Playgroud) 在8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]标准中,
显式默认函数和隐式声明函数统称为默认函数,实现应为它们提供隐式定义(12.1 12.4,12.8),这可能意味着将它们定义为已删除.如果特殊成员函数是用户声明的,并且在其第一个声明中未明确默认或删除,则由用户提供.用户提供的显式默认函数(即,在第一次声明后显式默认)是在明确默认的位置定义的; 如果将这样的函数隐式定义为已删除,则该程序格式错误. [注意:在第一次声明后将函数声明为默认值可以提供高效的执行和简洁的定义,同时为不断发展的代码库启用稳定的二进制接口.-结束语]
最后的注释是什么意思?从我所看到的,在第一次声明之后将函数声明为默认将使用户提供的函数,从而使函数变得非常简单,因此要么使类型具有非平凡的默认构造函数,要么使类型非常简单-copyable,当然使类型非平凡和非POD,同时仍然具有提供函数实际定义的实现.但我不明白这是如何导致" provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base"的.任何想法都是受欢迎的,现实世界的例子受到高度赞赏.谢谢.
这种类型的一个例子:
struct A {
A();
};
A::A() = default;
Run Code Online (Sandbox Code Playgroud)