lin*_*ker 43 c++ default-constructor effective-c++ empty-class
在Effective C++一书中,我看到了以下段落:
结果,如果你写
Run Code Online (Sandbox Code Playgroud)class Empty{};
它基本上和你写的一样:
Run Code Online (Sandbox Code Playgroud)class Empty { public: Empty() { ... } Empty(const Empty& rhs) { ... } ~Empty() { ... } Empty& operator=(const Empty& rhs) { ... } // copy assignment operator };
以下代码将导致生成每个函数:
Run Code Online (Sandbox Code Playgroud)Empty e1; Empty e2(e1); e2 = e1;
但是在拆解通过编译上面的代码创建的可执行文件之后,我意识到并非如此:没有任何函数被调用.
这是主要的汇编代码:
00000000004006cd <main>:
4006cd: 55 push %rbp
4006ce: 48 89 e5 mov %rsp,%rbp
4006d1: b8 00 00 00 00 mov $0x0,%eax
4006d6: 5d pop %rbp
4006d7: c3 retq
Run Code Online (Sandbox Code Playgroud)
段中没有任何名为"Empty"的函数.text
.
那么在我们调用构造函数或赋值空类之后,编译器的行为究竟是什么?这本书说它会产生一些功能吗?如果是这样,他们存放在哪里?
mks*_*eve 54
这些函数存在,但可以内联.
当编译器内联函数时,它意识到它们是无操作,并且没有生成代码.
本书的内容在某种程度上是正确的,编辑器为内联和直接调用创建了名义函数.
但是生成的代码是空的,因此优化编译器将删除函数的任何证据(设置this指针),并且永远不会直接调用函数.
本书并不是真正试图解释生成的代码,而是创建类的影响,以及它为正常操作生成的"隐藏"函数.
650*_*502 21
确实为类生成了这些方法,但它们生成为"内联".
因为它们是逐个成员的实现(例如,复制构造函数将复制构造所有成员),当它class
为空时,实际上没有在它们中完成任务,并且内联它们只是不可见的.
然而,记住这些方法自动获得实现是非常重要的...例如代码
struct Foo {
char *buf;
Foo() : buf(new char[10]) {}
~Foo() { delete[] buf; }
};
Run Code Online (Sandbox Code Playgroud)
因为自动生成的复制构造函数和赋值代码是错误的,并且会导致多次删除缓冲区.
它不是因为已经编写过的东西,而是因为没有编写的东西,这很棘手.这就是为什么要记住C++会自动为你写的东西非常重要的原因:如果那个实现是你想要的那么完美,但如果不是,那么通过提供正确的实现或禁止创建或使用错误的代码来修复它.
你和这本书是从不同的抽象层面来看待这种情况的.
本书使用术语"生成"来指代由编译器隐式定义到抽象C++程序中的C++函数.这绝对确实发生了.
您将其解释为在翻译的程序中实际生成实际机器代码.这不是它的意思.只要保持原始抽象程序的语义,实际机器代码的生成始终受编译器的异想天开.
因此,这本书当然不是不正确的,尽管为了清晰起见,我可能会使用不同的词.坚持标准术语永远不会伤害.
归档时间: |
|
查看次数: |
3287 次 |
最近记录: |