I have encountered the following strange situation: I have managed to have a global static variable with two instances ... Is this normal or is this a bug in the compiler or is this a hidden realm of C++? The following reproduction is an extract from a larger project (where the behaviour is the same), obviously the names were changed to protect the culprit (and yes, I know there are memory leaks in this code).
Here comes the code:
// other.h #ifndef _OTHER_H_ #define _OTHER_H_ struct other { long longer; int inter; char charer; }; void dosomething(); #endif And
// other.cpp #include "other.h" #include "util.h" void dosomething() { other* something = alloc_mem(other, 4); } And
// util.h #ifndef _UTIL_H_ #define _UTIL_H_ #include <memory.h> #include <string> #include "test_class.h" template <class T> T* allocate(size_t count, const char* f, long l, const char* sth) { T* tmp = new T[count]; memset(tmp, 0, count * sizeof(T)); test_class<T*>::instance().throwIn(tmp, f, l, sth, count); return tmp; } #define alloc_mem(type,count) allocate<type>(count, __FILE__, __LINE__, (char*)0) #endif And
// main.cpp #include "other.h" #include "util.h" int main() { int* i = alloc_mem(int, 1); int* i1 = alloc_mem(int, 20); char* c = alloc_mem(char, 1); dosomething(); int* i3 = alloc_mem(int, 1); } And the main part:
// test_class.h #ifndef test_class_H #define test_class_H #include <stdlib.h> #include <iostream> #include <typeinfo> #include <cxxabi.h> static long int all_alloc = 0; // THIS will get linked in two times! template <typename T> class test_class { private: test_class() {} static test_class<T>* pinstance; public: ~test_class() {} static test_class& instance() { if(pinstance == NULL) { pinstance = new test_class(); } return *pinstance; } void throwIn(T item, const char* file, long line, const char* _compiler, long count) { int status; char* s = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) ; std::cout << "request:" << sizeof(T) * count << " bytes, type:" << s << " @ "<< file << ":" << line << " global_addr:" << &all_alloc << std::endl; all_alloc += sizeof(T) * count ; free(s); std::cout<<"All memory:" << all_alloc << std::endl; } }; template <class T> test_class<T>* test_class<T>::pinstance = NULL; #endif So, you have to compile this as:
g++ main.cpp other.cpp -o test and the run it, and:
$ ./test request:8 bytes, type:int* @ main.cpp:6 global_addr:0x6022d8 All memory:8 request:160 bytes, type:int* @ main.cpp:7 global_addr:0x6022d8 All memory:168 request:8 bytes, type:char* @ main.cpp:8 global_addr:0x6022d8 All memory:176 request:32 bytes, type:other* @ other.cpp:6 global_addr:0x6022f8 All memory:32 request:8 bytes, type:int* @ main.cpp:11 global_addr:0x6022d8 All memory:184 so, as I could see with a pretty big surprise, I have two global addresses for all_alloc... Indeed, nm -C test shows:
00000000006022d8 b all_alloc 00000000006022f8 b all_alloc So, obviously the questions:
Why? How is this possible? Is there something allowing this kind of behaviour or is this a bug somewhere in the compiler or linker?
all_alloc. Each file that includestest_class.his going to get their ownall_alloc._OTHER_H_) and names that contain two consecutive underscores are reserved to the implementation. Don't use them.