返回信息流我记得静态局部变量应该是在main函数执行之前就占内存了,《more effective c++》的这段话是不是错了?
条款26 p133
“class拥有一个static对象”的意思是:即使从未被用到,它也会被构造(及析构)。相反地“函数拥有一个static对象”的意思是:此对象在函数第一次被调用时才产生。如果该函数从未被调用,这个对象也就绝不会诞生(然后你必须付出代价,在函数每次被调用时检查对象是否需要诞生)。C++的一个哲学基础是,你不应该为你并不使用的东西付出任何代价,而“将打印机这类对象定义为函数内的一个static”,正是固守此哲学的一种做法。这是你应该尽可能坚持的一个哲学。
这是一条镜像帖。来源:北邮人论坛 / cpp / #90873同步于 2016/4/2
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
静态局部对象的构造时机
xiaobing307
2016/4/2镜像同步4 回复
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
或许,这是C++能做到的最好的了吧。
在有虚拟机(比如Java)的情况下,如果代码是JIT编译的,编译器可以在函数里插入一个跳转,使得第一次执行的时候跳到一个地方初始化对象,然后进行code patching,把那个跳转指令覆盖成NOP。这样以后再执行就不会有代价(至少极低。而从Ivy Bridge开始,NOP指令可以在CPU的前端就直接抛弃掉,完全不占用执行单元,加一两个NOP不会影响性能)。
但是C++没有虚拟机。编译器不会向运行时提供任何关于代码的信息。能够管理运行时环境的,也就只有装载器(ld-linux.so)和运行时库(libc,libstdc++,libgcc)了。后者做不了code patching(没有信息)。前者能做的,也只有“把elf文件里的各个段”,“比如.text,.data什么的映射到内存里”,“把某些段初始化成0”,“解析函数名、变量名的装载后的实际地址”之类的简单的事。即使程序开始了,libc,libstdc++,libgcc能做的,也只有通过“读取某个特殊段(.init_array)里的函数表,在main函数执行之前,把里面每个函数都执行一遍”来初始化静态变量了。
理想很丰满,现实很骨感。C++这个没有虚拟机的语言,做这种动态的事情很不擅长。所以,“你不应该为你并不使用的东西付出任何代价”,在我看来只是一个C++信徒的幻想,和“没有虚拟机”这一弱点的遮羞布而已。就像RAII一样,C++鼓吹用RAII分配内存,但由于没有垃圾回收,也无法精确地确定内存里哪些部分是引用,所以在频繁分配和释放内存的情况下,C++的内存分配效率是低于有垃圾回收的语言的(Python、PHP之类的朴素引用计数不算,起码JVM、.NET虚拟机这些有高效垃圾回收的虚拟机的内存管理效率可以超过C++)。C++的支持者也在以“你不应该为你并不使用的东西付出任何代价”的说法为RAII辩护,但RAII并不适合内存管理。管理其他资源(如已经打开的文件、网络什么的)倒是一个不错的模式。实际上标准库里的string拷贝,就算有了COW,50%的情况下也还是要进行深拷贝的。
静态局部对象是在main函数执行之前就分配了内存,但是在第一次函数调用时才执行构造函数进行初始化??
相当于不管函数调不调用,都会分配sizeof(对象)的内存?
【 在 nuanyangyang 的大作中提到: 】
: 或许,这是C++能做到的最好的了吧。
: 在有虚拟机(比如Java)的情况下,如果代码是JIT编译的,编译器可以在函数里插入一个跳转,使得第一次执行的时候跳到一个地方初始化对象,然后进行code patching,把那个跳转指令覆盖成NOP。这样以后再执行就不会有代价(至少极低。而从Ivy Bridge开始,NOP指令可以在CPU的前端就直接抛弃掉,完全不占用执行单元,加一两个NOP不会影响性能)。
: 但是C++没有虚拟机。编译器不会向运行时提供任何关于代码的信息。能够管理运行时环境的,也就只有装载器(ld-linux.so)和运行时库(libc,libstdc++,libgcc)了。后者做不了code patching(没有信息)。前者能做的,也只有“把elf文件里的各个段”,“比如.text,.data什么的映射到内存里”,“把某些段初始化成0”,“解析函数名、变量名的装载后的实际地址”之类的简单的事。即使程序开始了,libc,libstdc++,libgcc能做的,也只有通过“读取某个特殊段(.init_array)里的函数表,在main函数执行之前,把里面每个函数都执行一遍”来初始化静态变量了。
: ...................
严格地说,这些都是实现细节,但提前分配空间更容易实现。
【 在 xiaobing307 的大作中提到: 】
: 静态局部对象是在main函数执行之前就分配了内存,但是在第一次函数调用时才执行构造函数进行初始化??
: 相当于不管函数调不调用,都会分配sizeof(对象)的内存?