3

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?

2
  • This "test_class.h" directly above the static you question is a fairly strong indicator this is in a header, and your command line suggests two source files are including it, each getting their own all_alloc. Each file that includes test_class.h is going to get their own all_alloc. Commented Nov 21, 2013 at 20:45
  • This isn't the problem, but names that begin with an underscore followed by a capital letter (_OTHER_H_) and names that contain two consecutive underscores are reserved to the implementation. Don't use them. Commented Nov 22, 2013 at 18:57

2 Answers 2

6

In this case, I don't think you want to declare your all_alloc static. In this case, it means that the linkage is internal. In your case, you get two copies since two files include the header.

If you remove static, then you will have two copies that clash, and result in a linker error. Which is not good.

I believe what you want to do is to change static to extern, then in one cpp file, define the variable and its value.

header:

extern long int all_alloc; 

cpp:

long int all_alloc = 0; 

This will provide one copy of all_alloc that is shared among your code.

Sign up to request clarification or add additional context in comments.

Comments

0

When you have global variable it already has static duration, so static keyword means something different for it. As you have class definition in the file you define your global static variable I assume that is a header. Why it is bad idea to use static global variable in header and what you will get you can read here So answer is: it is expected behavior and not a bug.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.