c++在空类中编写和调用什么函数?
What function does C++ write and call in an empty class?
在Effective c++ 这本书中,我看到了下面的段落:
因此,如果您写入class Empty{};
本质上和你这样写是一样的:
class Empty { public: Empty() { ... } Empty(const Empty& rhs) { ... } ~Empty() { ... } Empty& operator=(const Empty& rhs) { ... } // copy assignment operator };
以下代码将生成每个函数:
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
在.text
段中没有名为"Empty"的函数
那么在调用空类的构造函数或赋值之后,编译器的行为究竟是什么?它能像书上说的那样产生一些函数吗?如果有,它们存储在哪里?
函数存在,但可以内联。
当编译器内联函数时,它意识到它们是无操作的,并且没有生成代码。
书上所说的在某种程度上是正确的,名义函数是由编译器创建的,用于内联和直接调用。
但是生成的代码是空的,因此优化编译器将删除函数的任何证据(设置一个this指针),并且函数永远不会被直接调用。
这本书并不是真正试图解释生成的代码,而是创建类的影响,以及它为正常操作生成的"隐藏"函数。
这些方法确实是为类生成的,但它们是以"inline"方式生成的。
由于它们是逐成员实现(例如,复制构造函数将复制构造所有成员),当class
为空时,它们实际上没有做任何事情,并且是内联的,它们只是不可见的。
记住这些方法是自动实现的,这一点非常重要。例如代码
struct Foo {
char *buf;
Foo() : buf(new char[10]) {}
~Foo() { delete[] buf; }
};
有bug,因为自动生成的复制构造函数和赋值代码是错误的,会导致多次删除缓冲区。
有bug不是因为写了什么东西,而是因为写了而不是,这很棘手。这就是为什么记住c++会自动为你编写的东西是极其重要的:如果实现是你想要的,那么它是完美的,但如果不是,那么通过提供正确的实现来修复它,或者禁止创建或使用错误的代码。
你和这本书是从不同的抽象层次来处理这种情况的。
书中使用术语"生成"来指编译器隐式地将c++函数定义为抽象的c++程序。这绝对会发生。
你把它解释为在翻译的程序中实际生成的实际机器代码。不是这个意思。只要保持原始抽象程序的语义,实际机器代码的生成总是受编译器的影响。
因此,这本书当然不是不正确的,尽管为了清楚起见,我可能会使用不同的词。使用标准术语永远不会有坏处。
- 什么时候调用组成单元对象的析构函数
- 什么时候调用析构函数
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- boost odeint什么时候真正调用观测者
- unique_ptr:在分配之前调用 reset 有什么效果
- 是什么让放置新调用对象的构造函数?
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 什么是仅调用一次并调用参数的控制台应用
- 使用动态链接加载程序 <dlfcn.h> 而不是直接函数调用的目的是什么?
- 什么时候可以使用常量装饰调用我的重载函数?
- 如果结构中的字符串比使用的 p/调用签名长或短,会发生什么情况?
- 在 if 条件下调用什么重载运算符
- 一个类的构造函数,为另一个类进行强制转换.将调用什么函数
- R6025 纯虚函数调用:什么是以及如何解决
- 当按下Alt-Enter键时调用什么函数
- c++在空类中编写和调用什么函数?
- 在这种情况下调用什么构造函数