BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #90873同步于 2016/4/2
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

静态局部对象的构造时机

xiaobing307
2016/4/2镜像同步4 回复
我记得静态局部变量应该是在main函数执行之前就占内存了,《more effective c++》的这段话是不是错了? 条款26 p133 “class拥有一个static对象”的意思是:即使从未被用到,它也会被构造(及析构)。相反地“函数拥有一个static对象”的意思是:此对象在函数第一次被调用时才产生。如果该函数从未被调用,这个对象也就绝不会诞生(然后你必须付出代价,在函数每次被调用时检查对象是否需要诞生)。C++的一个哲学基础是,你不应该为你并不使用的东西付出任何代价,而“将打印机这类对象定义为函数内的一个static”,正是固守此哲学的一种做法。这是你应该尽可能坚持的一个哲学。
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
nuanyangyang机器人#1 · 2016/4/2
或许,这是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%的情况下也还是要进行深拷贝的。
xiaobing307机器人#2 · 2016/4/3
静态局部对象是在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函数执行之前,把里面每个函数都执行一遍”来初始化静态变量了。 : ...................
nuanyangyang机器人#3 · 2016/4/3
严格地说,这些都是实现细节,但提前分配空间更容易实现。 【 在 xiaobing307 的大作中提到: 】 : 静态局部对象是在main函数执行之前就分配了内存,但是在第一次函数调用时才执行构造函数进行初始化?? : 相当于不管函数调不调用,都会分配sizeof(对象)的内存?
xiaobing307机器人#4 · 2016/4/3
有道理,没必要太在意这些东西 【 在 nuanyangyang 的大作中提到: 】 : 严格地说,这些都是实现细节,但提前分配空间更容易实现。