Given is a class with a static member.
class BaseClass
{
public:
static std::string bstring;
};
String has obviously to be default-initialized outside of the class.
std::string BaseClass::bstring {"."};
If I include the above line in the header along with the class, I get a symbol multiply defined error. It has to be defined in a separate cpp file, even with include guards or pragma once.
Isn't there a way to define it in the header?
You can't define a static member variable more than once. If you put variable definitions into a header, it is going to be defined in each translation unit where the header is included. Since the include guards are only affecting the compilation of one translation unit, they won't help, either.
However, you can define static member functions! Now, at first sight that may not look as if it could help except, of course, that function can have local static variable and returning a reference to one of these behaves nearly like a static member variable:
static std::string& bstring() { static std::string rc{"."}; return rc; }
The local static variable will be initialized the first time this function is called. That is, the construction is delayed until the function is accessed the first time. Of course, if you use this function to initialize other global objects it may also make sure that the object is constructed in time. If you use multiple threads this may look like a potential data race but it isn't (unless you use C++03): the initialization of the function local static variable is thread-safe.
In C++17 you can use inline variables, which you can use even outside classes.
The inline specifier, when used in a decl-specifier-seq of a variable with static storage duration (static class member or namespace-scope variable), declares the variable to be an inline variable.
A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.⁽¹⁾
For example:
class Someclass {
public:
inline static int someVar = 1;
};
Or,
namespace SomeNamespace {
inline static int someVar = 1;
}
⁽¹⁾ https://en.cppreference.com/w/cpp/language/inline
Regarding
” Isn't there a way to define [the static data member] in the header?
Yes there is.
template< class Dummy >
struct BaseClass_statics
{
static std::string bstring;
};
template< class Dummy >
std::string BaseClass_statics<Dummy>::bstring = ".";
class BaseClass
: public BaseClass_statics<void>
{};
An alternative is to use a function, as Dietmar suggested. Essentially that is a Meyers' singleton (google it).
Edit: Also, since this answer was posted we've got the inline object proposal, which I think is accepted for C++17.
Anyway, think twice about the design here. Globals variables are Evil™. This is essentially a global.
To keep the definition of a static value with the declaration in C++11
a nested static structure can be used. In this case the static member
is a structure and has to be defined in a .cpp file, but the values
are in the header.
class BaseClass
{
public:
static struct _Static {
std::string bstring {"."};
} global;
};
Instead of initializing individual members the whole static structure is initialized:
BaseClass::_Static BaseClass::global;
The values are accessed with
BaseClass::global.bstring;
Note that this solution still suffers from the problem of the order of
initialization of the static variables. When a static value is used to
initialize another static variable, the first may not be initialized,
yet.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In this case the static variable headers will contain either { "" }
or { ".h", ".hpp" }, depending on the order of initialization created by the linker.
§3.2.6 and the following paragraphs from the current c++ 17 draft (n4296) define the rules when more than one definition can be present in different translation units:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements. Given
such an entity named D defined in more than one translation unit, then [...]
Obviously definitions of static data members of class type are not considered to appear in multiple translations units. Thus, according to the standard, it is not allowed.
The suggested answers from Cheers and hth. - Alf and Dietmar are more kind of a "hack", exploiting that definitions of
static data member of a class template (14.5.1.3)
and
inline function with external linkage (7.1.2)
are allowed in multiple TU ( FYI: static functions defined inside a class definition have external linkage and are implicitly defined as inline ) .
No, it can't be done in a header - at least not if the header is included more than once in your source-files, which appears to be the case, or you wouldn't get an error like that. Just stick it in one of the .cpp files and be done with it.
UPDATE: My answer below explains why this cannot be done in the way suggested by the question. There are at least two answers circumventing this; they may or may not solve the problem.
The bstring static member has to be linked to a specific memory address. For this to happen, it has to appear in a single object file, therefore it has to appear in a single cpp file. Unless you're playing with #ifdef's to make sure this happens, what you want cannot be done in the header file, as your header file may be included by more than one cpp files.
Related
I just wrote a class with some static data members, but now I am getting errors about "undefined references". Why doesn't this work? What am I doing wrong?
_(Note: This is meant to be an entry to [Stack Overflow's C++ FAQ](https://stackoverflow.com/questions/tagged/c++-faq). If you want to critique the idea of providing an FAQ in this form, then [the posting on meta that started all this](https://meta.stackexchange.com/questions/68647/setting-up-a-faq-for-the-c-tag) would be the place to do that. Answers to that question are monitored in the [C++ chatroom](https://chat.stackoverflow.com/rooms/10/c-lounge), where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)_
To understand this, you should have a good understanding of compiling and linking, and the differences between declarations and definitions.
Consider the following class:
//In header file
class Example {
static bool exampleStaticMember;
};
Here, exampleStaticMember is declared but not defined. This means that if exampleStaticMember is used in a way that means that it must have an address then there must be a separate definition for it. In general, no declaration of a static data member in a class definition is a definition of that member.
The required declaration is usually put in the cpp file which contains the other definitions for the members of the class. It must be in the same namespace as the class definition. The definition typically looks like:
//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember;
The definition can be put in any cpp file, but it should not be put in the header with the class, because that would be likely to break the One Definition Rule.
As a special case, if the static member variable is an const integral or enumeration type then it can have an initialiser in the class definition:
//In header file
class Example {
static const int initialised = 15;
};
In this case, the definition in the cpp file is still required, but it is not allowed to have an initialiser:
//In source file
//Note: no initialiser!
const int Example::initialised;
Static members that have been initialised like this can be used in constant expressions.
Templates
For a static data member of a template, things are slightly different. The static member should be defined in the header along with the rest of the class:
//In header file
template<typename T>
class Example {
static int exampleInt;
static T exampleT;
}
template<typename T> int Example<T>::exampleInt;
template<typename T> T Example<T>::exampleT;
This works because there is a specific exception to the One Definition Rule for static data members of class templates.
Other uses of static
When the static keyword is applied to functions and objects that are not in a class scope it can take on a very different meaning.
When applied to objects in a function scope, it declares an object that is initialised in the first execution of the function and that subsequently keeps its value between function calls.
When applied to objects or functions at namespace scope (outside of any class or function definition), it declares objects or functions with internal linkage. This usage is deprecated for objects, as the unnamed-namespace provides a better alternative.
You have to instantiate static members defined in a header in a .cpp file. For example:
// foo.h
class foo {
static int X;
};
// foo.cpp
#include "foo.h"
int foo::X = 0;
struct A
{
static void f();
};
static void A::f() {} //illegal
Why's this not allowed? Am asking this because the rule seems inconsistent with other keywords.
You must put constexpr on both.
You can put inline on both, but you can also omit one of them. This is useful that you can omit inline in class definition, which is not important information of the interface.
But the rules for static on class members doesn't really make sense. Shouldn't it be consistent with constexpr?
I know static means internal linkage for namespace-scope functions, and this partly explains the current shape. But isn't distinguishing between free functions and class member functions having no ambiguity in namespace scope? For example, if you write static void A::f() {} it's unambiguous that you're defining a member function of A, if A is a class name.
The static in class have other meaning the static in a global or namespace.
when you declared symbol as static in the class, you don't want it to be a global static.
1. static member
In the class it is mean the symbol is class related not object related, means for member variable, there is only one instance for all the objects, and for function, it doesn't have access to non static members, which are object oriented. .
2. static global
In global scope, the static indicate the object or function is local only, and can't be exported (like using extern) to other files. in addition it let you use same name in other file for other variable. so if it located in header file, any file including the header, will have different instance of the symbol.
Therefore if you were allowed to use it in the global scope for a member, then there was an ambiguity.
For static member variables in C++ class - the initialization is done outside the class. I wonder why? Any logical reasoning/constraint for this? Or is it purely legacy implementation - which the standard does not want to correct?
I think having initialization in the class is more "intuitive" and less confusing.It also gives the sense of both static and global-ness of the variable. For example if you see the static const member.
Fundamentally this is because static members must be defined in exactly one translation unit, in order to not violate the One-Definition Rule. If the language were to allow something like:
struct Gizmo
{
static string name = "Foo";
};
then name would be defined in each translation unit that #includes this header file.
C++ does allow you to define integral static members within the declaration, but you still have to include a definition within a single translation unit, but this is just a shortcut, or syntactic sugar. So, this is allowed:
struct Gizmo
{
static const int count = 42;
};
So long as a) the expression is const integral or enumeration type, b) the expression can be evaluated at compile-time, and c) there is still a definition somewhere that doesn't violate the one definition rule:
file: gizmo.cpp
#include "gizmo.h"
const int Gizmo::count;
In C++ since the beginning of times the presence of an initializer was an exclusive attribute of object definition, i.e. a declaration with an initializer is always a definition (almost always).
As you must know, each external object used in C++ program has to be defined once and only once in only one translation unit. Allowing in-class initializers for static objects would immediately go against this convention: the initializers would go into header files (where class definitions usually reside) and thus generate multiple definitions of the same static object (one for each translation unit that includes the header file). This is, of course, unacceptable. For this reason, the declaration approach for static class members is left perfectly "traditional": you only declare it in the header file (i.e. no initializer allowed), and then you define it in a translation unit of your choice (possibly with an initializer).
One exception from this rule was made for const static class members of integral or enum types, because such entries can for Integral Constant Expressions (ICEs). The main idea of ICEs is that they are evaluated at compile time and thus do no depend on definitions of the objects involved. Which is why this exception was possible for integral or enum types. But for other types it would just contradict the basic declaration/definition principles of C++.
It's because of the way the code is compiled. If you were to initialize it in the class, which often is in the header, every time the header is included you'd get an instance of the static variable. This is definitely not the intent. Having it initialized outside the class gives you the possibility to initialize it in the cpp file.
Section 9.4.2, Static data members, of the C++ standard states:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a const-initializer which shall be an integral constant expression.
Therefore, it is possible for the value of a static data member to be included "within the class" (by which I presume that you mean within the declaration of the class). However, the type of the static data member must be a const integral or const enumeration type. The reason why the values of static data members of other types cannot be specified within the class declaration is that non-trivial initialization is likely required (that is, a constructor needs to run).
Imagine if the following were legal:
// my_class.hpp
#include <string>
class my_class
{
public:
static std::string str = "static std::string";
//...
Each object file corresponding to CPP files that include this header would not only have a copy of the storage space for my_class::str (consisting of sizeof(std::string) bytes), but also a "ctor section" that calls the std::string constructor taking a C-string. Each copy of the storage space for my_class::str would be identified by a common label, so a linker could theoretically merge all copies of the storage space into a single one. However, a linker would not be able to isolate all copies of the constructor code within the object files' ctor sections. It would be like asking the linker to remove all of the code to initialize str in the compilation of the following:
std::map<std::string, std::string> map;
std::vector<int> vec;
std::string str = "test";
int c = 99;
my_class mc;
std::string str2 = "test2";
EDIT It is instructive to look at the assembler output of g++ for the following code:
// SO4547660.cpp
#include <string>
class my_class
{
public:
static std::string str;
};
std::string my_class::str = "static std::string";
The assembly code can be obtained by executing:
g++ -S SO4547660.cpp
Looking through the SO4547660.s file that g++ generates, you can see that there is a lot of code for such a small source file.
__ZN8my_class3strE is the label of the storage space for my_class::str. There is also the assembly source of a __static_initialization_and_destruction_0(int, int) function, which has the label __Z41__static_initialization_and_destruction_0ii. That function is special to g++ but just know that g++ will make sure that it gets called before any non-initializer code gets executed. Notice that the implementation of this function calls __ZNSsC1EPKcRKSaIcE. This is the mangled symbol for std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&).
Going back to the hypothetical example above and using these details, each object file corresponding to a CPP file that includes my_class.hpp would have the label
__ZN8my_class3strE for sizeof(std::string) bytes as well as assembly code to call __ZNSsC1EPKcRKSaIcE within its implementation of the __static_initialization_and_destruction_0(int, int) function. The linker can easily merge all occurrences of __ZN8my_class3strE, but it cannot possibly isolate the code that calls __ZNSsC1EPKcRKSaIcE within the object file's implementation of __static_initialization_and_destruction_0(int, int).
I think the main reason to have initialization done outside the class block is to allow for initialization with return values of other class member functions. If you wanted to intialize a::var with b::some_static_fn() you'd need to make sure that every .cpp file that includes a.h includes b.h first. It'd be a mess, especially when (sooner or later) you run into a circular reference that you could only resolve with an otherwise unnecessary interface. The same issue is the main reason for having class member function implementations in a .cpp file instead of putting everything in your main class' .h.
At least with member functions you do have the option to implement them in the header. With variables you must do the initialization in a .cpp file. I don't quite agree with the limitation, and I don't think there's a good reason for it either.
I'm working on compiling Cppcheck on AIX using xlC. Every checker class is derived from a Check class, whose constructor is responsible for registering that type of checker in a global static list.
Here's the relevant part of the code in question (filenames link to full source on Github):
check.h
class Check {
public:
Check() {
instances().push_back(this);
instances().sort();
}
static std::list<Check *> &instances() {
static std::list<Check *> _instances;
return _instances;
}
// ...
};
checkbufferoverrun.h
class CheckBufferOverrun: public Check {
// ...
};
checkbufferoverrun.cpp
// Register this check class (by creating a static instance of it)
namespace
{
CheckBufferOverrun instance;
}
Notice how the _instances static variable is declared inside a static function in the header file (there is no corresponding check.cpp file). When compiled with g++, the compiler and linker work together to ensure that there is only one implementation of the static instances() function, and therefore only one instance of the static _instances list. All the different checker classes instantiated in different .cpp files get registered in the same _instances list together.
However, under AIX's xlC, this same code ends up creating a different instances() function for every .cpp file in which it is included, which each having a different static _instances list. So there is no longer a single central _instances list, which causes Cppcheck to not run most of its checks.
Which compiler's behaviour is correct in this case?
Update: This question is not about how to fix the problem, I've already done that. I'm curious about which behaviour is correct.
g++ has the correct behavior: there should be exactly one instance of the object. The C++ Standard says (C++03 7.1.2/4):
A static local variable in an extern inline function always refers to the same object.
Because the class has external linkage, the static member function also has external linkage, per C++03 3.5/5:
a member function...has external linkage if the name of the class has external linkage.
Because the member function is defined in the class definition, it is an inline function, per C++03 7.1.2/3:
A function defined within a class definition is an inline function.
In this particular case g++ is correct (assuming that the instances() static member function returns a reference, that is a typo, right?). You might want to move the definition of the instances() function to a cpp file, that should be a work around in xlc.
Correct it to:
static std::list<Check *>& instances();
// check.cpp
std::list<Check *> & Check::instances()
{
static std::list<Check *> _instances;
return _instances;
}
If you inline the function in the header file, each compilation unit will initially compile its own definition. However at link-time they should be reduced to one instance because of the One-Definition Rule.
I am sure you are aware, of course, that your constructor to Check is not thread-safe. Your singleton constructor is also not totally thread-safe because although the ODR ensures the threads between them can only create one instance, the constructor of list is not atomic and therefore I am not sure it is guaranteed to be completely constructed before the other thread sees it.
For a totally thread-safe way of constructing singletons or non-atomic statics, you can use boost::once.
For static member variables in C++ class - the initialization is done outside the class. I wonder why? Any logical reasoning/constraint for this? Or is it purely legacy implementation - which the standard does not want to correct?
I think having initialization in the class is more "intuitive" and less confusing.It also gives the sense of both static and global-ness of the variable. For example if you see the static const member.
Fundamentally this is because static members must be defined in exactly one translation unit, in order to not violate the One-Definition Rule. If the language were to allow something like:
struct Gizmo
{
static string name = "Foo";
};
then name would be defined in each translation unit that #includes this header file.
C++ does allow you to define integral static members within the declaration, but you still have to include a definition within a single translation unit, but this is just a shortcut, or syntactic sugar. So, this is allowed:
struct Gizmo
{
static const int count = 42;
};
So long as a) the expression is const integral or enumeration type, b) the expression can be evaluated at compile-time, and c) there is still a definition somewhere that doesn't violate the one definition rule:
file: gizmo.cpp
#include "gizmo.h"
const int Gizmo::count;
In C++ since the beginning of times the presence of an initializer was an exclusive attribute of object definition, i.e. a declaration with an initializer is always a definition (almost always).
As you must know, each external object used in C++ program has to be defined once and only once in only one translation unit. Allowing in-class initializers for static objects would immediately go against this convention: the initializers would go into header files (where class definitions usually reside) and thus generate multiple definitions of the same static object (one for each translation unit that includes the header file). This is, of course, unacceptable. For this reason, the declaration approach for static class members is left perfectly "traditional": you only declare it in the header file (i.e. no initializer allowed), and then you define it in a translation unit of your choice (possibly with an initializer).
One exception from this rule was made for const static class members of integral or enum types, because such entries can for Integral Constant Expressions (ICEs). The main idea of ICEs is that they are evaluated at compile time and thus do no depend on definitions of the objects involved. Which is why this exception was possible for integral or enum types. But for other types it would just contradict the basic declaration/definition principles of C++.
It's because of the way the code is compiled. If you were to initialize it in the class, which often is in the header, every time the header is included you'd get an instance of the static variable. This is definitely not the intent. Having it initialized outside the class gives you the possibility to initialize it in the cpp file.
Section 9.4.2, Static data members, of the C++ standard states:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a const-initializer which shall be an integral constant expression.
Therefore, it is possible for the value of a static data member to be included "within the class" (by which I presume that you mean within the declaration of the class). However, the type of the static data member must be a const integral or const enumeration type. The reason why the values of static data members of other types cannot be specified within the class declaration is that non-trivial initialization is likely required (that is, a constructor needs to run).
Imagine if the following were legal:
// my_class.hpp
#include <string>
class my_class
{
public:
static std::string str = "static std::string";
//...
Each object file corresponding to CPP files that include this header would not only have a copy of the storage space for my_class::str (consisting of sizeof(std::string) bytes), but also a "ctor section" that calls the std::string constructor taking a C-string. Each copy of the storage space for my_class::str would be identified by a common label, so a linker could theoretically merge all copies of the storage space into a single one. However, a linker would not be able to isolate all copies of the constructor code within the object files' ctor sections. It would be like asking the linker to remove all of the code to initialize str in the compilation of the following:
std::map<std::string, std::string> map;
std::vector<int> vec;
std::string str = "test";
int c = 99;
my_class mc;
std::string str2 = "test2";
EDIT It is instructive to look at the assembler output of g++ for the following code:
// SO4547660.cpp
#include <string>
class my_class
{
public:
static std::string str;
};
std::string my_class::str = "static std::string";
The assembly code can be obtained by executing:
g++ -S SO4547660.cpp
Looking through the SO4547660.s file that g++ generates, you can see that there is a lot of code for such a small source file.
__ZN8my_class3strE is the label of the storage space for my_class::str. There is also the assembly source of a __static_initialization_and_destruction_0(int, int) function, which has the label __Z41__static_initialization_and_destruction_0ii. That function is special to g++ but just know that g++ will make sure that it gets called before any non-initializer code gets executed. Notice that the implementation of this function calls __ZNSsC1EPKcRKSaIcE. This is the mangled symbol for std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&).
Going back to the hypothetical example above and using these details, each object file corresponding to a CPP file that includes my_class.hpp would have the label
__ZN8my_class3strE for sizeof(std::string) bytes as well as assembly code to call __ZNSsC1EPKcRKSaIcE within its implementation of the __static_initialization_and_destruction_0(int, int) function. The linker can easily merge all occurrences of __ZN8my_class3strE, but it cannot possibly isolate the code that calls __ZNSsC1EPKcRKSaIcE within the object file's implementation of __static_initialization_and_destruction_0(int, int).
I think the main reason to have initialization done outside the class block is to allow for initialization with return values of other class member functions. If you wanted to intialize a::var with b::some_static_fn() you'd need to make sure that every .cpp file that includes a.h includes b.h first. It'd be a mess, especially when (sooner or later) you run into a circular reference that you could only resolve with an otherwise unnecessary interface. The same issue is the main reason for having class member function implementations in a .cpp file instead of putting everything in your main class' .h.
At least with member functions you do have the option to implement them in the header. With variables you must do the initialization in a .cpp file. I don't quite agree with the limitation, and I don't think there's a good reason for it either.