Static keyword does not have the same meaning in C or C++ :
C's static ~= C++'s private
static keeps its meaning for functions in a specific compilation unit: the symbol is not exported and (in gcc 3.4), interesting compilation schemes can be applied (basically, the compiler can break the C calling convention since nobody outside the compilation unit would be able to call the function).
Note that the anonymous namespace is the C++ way to achieve this.
For classes, static declares class-wide methods and data (same as in Java).
That is, the static methods and data are not attached to a specific object, but to the class itself.
It is different from namespaces since the access keywords (”“public””, ”“protected””, ”“private””) apply
(a namespace is basically a class were all methods are static and everything is public.
of course, by using namespaces you get to use the ”“using”” and ”“using namespace”” keywords)
static variables declared inside classes are only declarations.
when you write :
class Foo { static myObject whatever; }
you HAVE to do a :
myObject Foo::whatever;
elsewhere (.cpp) in order to allocate the object
That is, you need to put the variable in a compilation unit in order to get it allocated.
Why ? Because you often have to define the class in a header.
If the static keyword would allocate the | the symbol would be allocated once in each compilation unit that includes the header.
Note that you have the same problem with functions and methods, but that the inline keyword forces the compiler to merge the symbols.
The exception is ”“static const””, at least for PODs. That is, you can do
class CPlusPlus { public: static const int m = 0; };
compiles on g++ not [[MSVC]]
# Microsoft (R) 32-bit C/C++ Standard Compiler Version 12.00.8168 for 80x86 # cplusplus.cpp(1) : error C2252: 'm' : # pure specifier can only be specified for functions
But only on integral types (int, char ..)
class CPlusPlus { public: static const float m = 0; };
# g++ -pedantic -c cplusplus.cpp cplusplus.cpp:1: error: ISO C++ forbids # initialization of member constant `m' of non-integral type `const float'
1st I suspected that the problem was related to C++ templates default allocators…. but Zif & Doudou helped and confirm that static members must be allocated in objects (.cpp)
But how comes that on final link Allocation is “mandatory” for some cases and not for others. Lets conclude that “it's mandatory when it is requiered” ?
# pr -t -o 1 -w 80 cppstatic.cpp
/// @author: www.Philippe.COVAL.free.fr /// PROJECT=cppstatic ; make ${PROJECT} && ./${PROJECT} ; rm ./${PROJECT} /// PROJECT=cppstatic ; make ${PROJECT} CXXFLAGS="-DMEMBER" && ./${PROJECT} ; rm ./${PROJECT} /// PROJECT=cppstatic ; make ${PROJECT} CXXFLAGS="-DMEMBER -DMEMBER_STATIC" && ./${PROJECT} ; rm ./${PROJECT}
#include <iostream> using namespace std; #define debug(x) cerr<<"# " <<(x)<<endl; /// template<class T> class TCls { public: T m; }; // #pragma instantiate TCls<int> // doenst not help either /// class Cls { public: static int main(int argc=0, char** arg = 0);
static Cls instance; // default allocator is (not really) called #ifdef MEMBER static TCls<int> mt; // default allocator is NOT called , why ? HELP #endif };
/// #ifdef STATIC_MEMBER TCls<int> Cls::mt; // default allocator is called #endif /// int Cls::main(int argc, char** argv ) { #ifndef MEMBER TCls<int> Cls::mt; // default allocator is called #endif mt.m = 1; return EXIT_SUCCESS; } /// int main(int argc, char* argv[[]] ) { Cls::instance.main(argc, argv); //ok Cls::main( argc, argv ); // ok debug(__PRETTY_FUNCTION__); //just print "main" return EXIT_SUCCESS; } /* g++ --version | head -1 g++ (GCC) 3.3.1 (Mandrake Linux 9.2 3.3.1-2mdk)
PROJECT=cppstatic ; make ${PROJECT} && ./${PROJECT} ; rm ./${PROJECT} g++ cppstatic.cpp -o cppstatic # int main(int, char**)
PROJECT=cppstatic ; make ${PROJECT} CXXFLAGS="-DMEMBER" && ./${PROJECT} ; rm ./${PROJECT} g++ -DMEMBER cppstatic.cpp -o cppstatic ccKZVVHu.o(.text+0xd): In function `Cls::main(int, char**)': : undefined reference to `Cls::mt' collect2: ld returned 1 exit status
PROJECT=cppstatic ; make ${PROJECT} CXXFLAGS="-DMEMBER -DSTATIC_MEMBER" && ./${PROJECT} ; rm ./${PROJECT} g++ -DMEMBER -DSTATIC_MEMBER cppstatic.cpp -o cppstatic # int main(int, char**)
//#ident "$Id:*" //EOF
<zif> explanation : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/class_15.asp
Don't forget that C++ is not Java and that macros are Evil. </zif>
<zif>And you, try to get better examples. C++ is a lazy language with lazy compilers.
If I add a public method 'void foo(){}' to Cls, If i call in main: 'Cls::instance.foo();' I will get:
/tmp/ccRMvkjc.o(.text+0x39): In function `main': : undefined reference to `Cls::instance' collect2: ld returned 1 exit status
Adding a 'Cls Cls::instance;' in the static part of the unit will correct this. What's your point, again ?
(BTW, editing other people's text on a wiki is quite rude)</zif>
<Doudou> well, it has to do with a #ifndef MEMBER which should be a #ifndef STATIC_MEMBER :) in the case were you only define MEMBER you only declare mt, you never allocate it.
C++ templates declaration is done when the compiler decides to do it .
Just read the gcc infopage for more informations on C++ template instanciation
</Doudou>