5 ms·
"By default, there is no exponential and mind blowing executable size increase." I'm sorry but that's not really true. If you compile with debugging informati
by jzwinck 12y ago
"By default, there is no exponential and mind blowing executable size increase."
I'm sorry but that's not really true. If you compile with debugging information included (with or without optimization), GCC will give you tons and tons of template name stuff in your compiled binary. I have one program that is over 100 MB and well over half of it seems to be template-related debugging stuff. It's unlikely that you could generate so many and such long symbols by hand if you weren't using templates. If you build without debugging symbols, or strip them, or separate them out, you may have different results, but I don't think that's the most common scenario for C++ users.
You can also wind up with actual instruction bloat too: a seemingly "high performance" function written with recursive templates may wind up with dozens of kilobytes of machine code thrashing your i-cache while a perfectly good "old style" function would do the same job with a hundred bytes. Disk may be cheap, but instruction cache is not.
- pkolaczk 12y agoEven a not very complex program written in modern C++ is going to use a lot of map, set, vector, unordered_map, iterator instantiations for different types. Even if some of them can be deduplicated by a smart-enough-linker, that's still a significant amount of code, added for little or no gain (most of code is not on critical path).
- cbsmith 12y agoIf the code isn't critical path, it really doesn't matter too much whether it was for much gain or not, no? ;-)
- pkolaczk 12y agoYeah, but that code still sits in memory, occupies space and takes non-zero time to load. It also takes free memory from the fragments of code that are on the critical path. Sometimes it doesn't matter (most desktop apps), sometimes it does (embedded software or system-level programming). Also, RAM usage of quite a lot of kinds of software is determined mostly by code size, not data size (e.g. word processors, spreadsheets, CAD software, IDEs, compilers) and startup-time is also determined typically by loading and dynamic linking time.
- cageface 12y agoDon't most operating systems memory-map executables in anyway? As long as the code is never paged it in shouldn't make any difference.
- cbsmith 12y agoThere is still link time if the types are shared across shared libraries (which happens a lot).
- deleted 12y ago[deleted]
- pkolaczk 12y agoAgree, but if the code is used even only once, it gets loaded to memory. So if you've got a complex_generic_container<T1, T2>, its code gets loaded for every combination of types used.
- cbsmith 12y agoIt gets loaded and then most likely paged out, particularly if your linker is profile guided (but even if not... rarely used code tends to get linked with other rarely used code). It's fair that if you want to optimize startup times, that first page in hurts, although generally with C++ is's more about the symbol linking overhead than anything else (and there are a lot of strategies for minimizing that, but it sure isn't want happens by default).
- dllthomas 12y agoThere is also cache to consider.
- cbsmith 12y agoThere is only cache to consider! ;-) Other than cache, there are plenty of tricks that can cure a lot of other ills, but cache is precious.
- corysama 12y agoDoes the program need to do the map, set, vector, iterator, ect... operations or does it not? If the work needs to be done then it needs to be instantiated in the code somehow. What is your proposed alternative?
- dllthomas 12y agoTo me, the parent seemed to be complaining about multiple copies of effectively the same map (or set, or vector, ...) code for different types, not the presence of the map (or ...) code in the first place. The latter is obviously unavoidable. The former is an efficiency trade-off between the optimization opportunities afforded by specialization and inlining, and the smaller instruction footprint of keeping the code generic.
- corysama 12y agoSo then, is the proposed alternative a library of containers and algorithms that are genericized via void pointers, memcpy sizes and function pointer predicates?
- dllthomas 12y agoI'd assume so. In principle you can get there without sacrificing type safety (http://en.wikipedia.org/wiki/Type_erasure http://en.wikipedia.org/wiki/Type_erasure). In practice, I don't know whether or not you can write type safe C++ that compiles that way.
- corysama 12y agoThis seems like a nice article series on the subject http://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i/ http://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i... Just getting started on it, it seems that the theme is that you can't have the same binary code work on different types without having a run-time indirection in there somewhere. But, you can use templates to keep that indirection convenient and type safe. And, you can structure your templates to only specialize a minimal amount of code necessary to interface your type into a non-specialized algorithm.
- cbsmith 12y agoI thought everyone stripped out debug info and shoved it in to a separate lzma compressed file these days... If you use C++11/C++14 constexpr (and don't screw it up ;-), you really can be assured that the computations will complete at compile time at which point you shouldn't have very much left for the compiler to deal with at run time. I guess in theory you could have i-cache issues and such, but in practice I've yet to see that happen.