Quote:Original post by bpoint
Quote:Original post by phresnel
Quote:Original post by bpoint
By simply adding virtual to the class's functions, the whole template becomes instanctiated, and all types of T are now required to implement everything the template requires even if they'll never use them.
Argh, yes, me and my bad Engrish. It happens when you live in a foreign country and only speak in your native tounge once a month to call home.
Actually, you're english is pretty good, and that was the reason why I assumed that you are wrong, and didn't assume that it was just bad wording :D
Quote:I suppose I should have said something like:
"By simply adding virtual to the functions in the class which I plan to derive from, those particular functions in the template incidentally become instanctiated as well, and all types of T are now required to implement the functions and operators used by the virtual template functions even if they'll never use them."
Better? :)
Hehe, indeed. Or shorter: "Making a class-template-member-function virtual causes that function to be instantiated eagerly (as compared to the lazy instantiation of non-virtual class-template-member-functions)." :)
Into more detail about why partially initialized vtables can cause PITA
Quote:Quote:Original post by Humble Me
While not impossible, it would cause a lot of epic PITA to manage a partially initialized, partially uninitialized vtable. It could cause PITA for the compiler, but could also end in performance trouble at runtime.
Yes, I didn't forget you said this. Again, I'm no compiler writer, but I still don't think it would be that difficult to maintain a partial vtable, which would have no affect on runtime performance. If you can show me where I am wrong in my thinking, please do. :)
The problems are mainly the same as the problems for implementing the keyword "export" (
"Why we can't afford export"), which is only implemented in one and only one C++ compiler frontend.
Most easily understood might be that C and C++ have so called "translation units", where a unit is, simply speaking, a single sourcecode file (as compared to header files). Virtually all C and C++ compilers will compile each single sourcefile into a corresonding, so-called "object file", which contains machine code (i.e. it contains compiled code; that code is not necessarily actual machine code), plus a directory of entities (functions, classes) that can be found in that object file. Finally, you pass all object-files to the "linker", who will assemble a working program from those, based on the information that can be found in the directories. At that final level, it is hard (as in PITA), not impossible, to do further optimizations and things like keeping track of the initialization status of vtables upon binary data.
To give an exemplary and heavily eased example for how compiling works in C and C++:
sourcefile-a.cppextern int alphaCentauri () ;int main () { alphaCentauri ();}
The compiler has only access to this sourcefile. This is also the reason why he can't inline the call to alphaCentauri(). So, he emits a request in form of a "missing reference" into the object file:
sourcefile-a.obj Contains: [main () : int] at 0x00 Missing References: [alphaCentauri () : int] at 0x04 Machine Code: 0x12 0x01 0x02 0x03 // let's assume here is a call instruction 0x00 0x41 0xa2 0xb3 0x30 0x21 0x92 0xc3 0x03 0x31 0x02 0xf3
sourcefile-a.cppint alphaCentauri () { return 0xBEEF;}
sourcefile-b.obj Contains: [alphaCentauri () : int] at 0x00 Missing References: Machine Code: 0xa2 0xb3 0xc6 0x41 0x02 0xf3 0x03 0x31 0x30 0xc3 0xBE 0xEF // heh, our "BEEF" :D 0x01 0x02 0x03 0x12
LinkingThe linker now has access to both object files and can do the final "Cleaning". He sees that in
sourcefile-a.obj there's a missing reference to a function with the signature "alphaCentauri () : int", so he looks up whether one of the other object-files
defines such function. If he can't find the definition, he emits something like
undefined reference to alphaCentauri() in sourcefile-a.obj+0x04
. But as we where clever, we passed all necessary object files to it, and so the linker can finally replace the dummy value with the actual address of alphaCentauri(). It now also becomes evident that this is also the time to transform all relative addresses into absolute ones.
Our final binary then looks like:
0x12 0x01 0x02 0x03 0x20 0x41 0xa2 0xb3 // 32 = 0x20 0x30 0x21 0x92 0xc3 0x03 0x31 0x02 0xf3 0xa2 0xb3 0xc6 0x41 // function "alphaCentauri()" starts here 0x02 0xf3 0x03 0x31 0x30 0xc3 0xBE 0xEF 0x01 0x02 0x03 0x12
Finally, some links to more information:
[Edited by - phresnel on April 23, 2009 7:36:30 AM]