I stumbled upon some C++11 code that looks like this:
// some_file.h
namespace blah {
class X {
public:
constexpr const static std::initializer_list<uint64> SOME_LIST =
{1,2,3};
};
}
// some_file.cpp
#include "some_file.h"
namespace blah {
constexpr const std::initializer_list<uint64> X::SOME_LIST;
}
Which compiles fine. I assume the definition in the cpp file is used to avoid symbol duplication in each file that includes the header (please correct me if I'm wrong).
I then tried the following:
// my_file.h
namespace bleh {
constexpr const static char SOME_CONSTANT[] = "yay";
}
// my_file.cpp
#include "my_file.h"
namespace bleh {
// if I add this or any other variation, compilation breaks!
//constexpr const static char SOME_CONSTANT[];
}
The code above does not work if I add an explicit definition in the .cpp file. So I am wondering: is there symbol duplication in the second case? If so, is there a way to define the variable without an enclosing class?
The static keywords mean two different things here:
When you declare a variable or function at file scope (global and/or namespace scope), the static keyword specifies that the variable or function has internal linkage. When you declare a variable, the variable has static duration and the compiler initializes it to 0 unless you specify another value.
When you declare a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all instances of the class. A static data member must be defined at file scope. An integral data member that you declare as const static can have an initializer.
C++ needs you to define static class members somewhere, because the class symbol is global (and so is your member). This can't be done in the header because of multiple definitions.
In the second case every compilation unit uses its own variable and there is no global symbol.
Related
I am a bit confused by the inline variable introduced by C++17. What are the differences between inline variable and inline static variable? Also will this be affected by scope?
inline T var_no_scope;
inline static T static_var_no_scope;
namespace scope {
inline T var_scope;
inline static T static_var_scope;
}
Any explanation will be appreciated!
At namespace scope:
inline static seems to be equivalent to just static.
inline on variables only has effect when you define the same variable in several translation units. Since static restricts the variable to a single TU, you can't have more than one definition.
At class scope:
inline can only appear on static variables.
It has its normal effect, allowing you to initialize the variable directly in the header. Either:
struct A
{
inline static int a = 42;
};
Or:
struct A
{
static int a;
};
inline int A::a = 42;
At function scope:
inline is not allowed.
For me it becomes more interesting when it is a data members. In C++17 you can declare your static data members as inline. The advantage is that you don't have to allocate space for them in a source file. For example:
class A
{
// Omitted for brevity
static inline int b = 0;
};
So int A::b; can be removed from the source file.
inline is applicable to variables only with static storage duration.
All of the variables in your example have namespace scope, giving them static storage duration. Declaring them inline has no net effect if they are static.
A variable inside a class, struct or union only has static storage duration if it is declared static. Those varibles must be static if they are to be inline.
Great answer about inline variables and why we want to use them can be found here. In short inline variable allows to have multiple definition of a variable (even across multiple files), that will result in one variable in memory. This allow constexpr global variables in header files.
header.h
namespace constants
{
inline constexpr double P = 1.11;
}
Behavior is undefined when definitions have different values, but this shouldn't be a problem when multiplication of definitions occur only due to header file.
Others have pointed to a nice application in classes:
template<typename T>
struct C
{
static inline constexpr int c = 10;
};
And then you can reference this variable anywhere, e.g. with:
C<int>::c;
The inline static variable can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition:
struct X
{
inline static int n = 1;
};
Inline variables eliminate the main obstacle to packaging C++ code as header-only libraries.
If you need to declare global variables that are shared between compilation units, declare them as inline variables in the header file.
Also will this be affected by scope?
Any of the following names declared at namespace scope have external linkage and also names declared without a namespace for external linkage including in multiple source files must be inline.
See this Example.
This link has valuable information about inline variables.
definition from c++ reference: citation: https://en.cppreference.com/w/cpp/language/inline
inline variable is defined as inline static keyword. Hence
inline static vartype yourvariablename // is a inline variable.
Interesting note about inline "A function defined entirely inside a class/struct/union definition, whether it's a member function or a non-member friend function, is implicitly an inline function if it is attached to the global module"(C++ 20)
Ok from personal experience here's why inline static is a really really big thing:
If all you need todo is initialize a static variable in a C++ file then you can remove the C++ file and use inline static initialization(but your code will require C++ 17 and up)
Initializing static variables in pre C++ 17 classname templates is just overly verbose. You would have to do something like:
template
class classname
{
static yourtype yourstaticvariable = yourvalue; // and you'll have to initialize it
};
template yourtype classname::yourstaticvariable = yourvalue;
OR with inline static you can just do:
template <class T>
class classname
{
static yourtype yourstaticvariable = yourvalue; // initialized
}
You can heavily exploit templates if you use inline static for initializing common things. Consider for instance the singleton where a inline static variable is perfect for tracking the instance and hence can be done in one file where before initializing the static variable would be painful. This becomes even more evident when you have multivariable templates.
You need less C++ include files and less lib projects if you exploit inline static for single C++ header. This can heavily trim down files in a big project.
But there some caveats with inline static:
You need C++ 17 and up
You have to pay attention to issues of putting your initialization in a .h file(which you probably want to do if you initialize with inline static). Although this isn't necessarily a inline static issue but the decision to potentially moving everything to a header could lead to possible issues like namespace collisions, reusing macros or other things if you not careful with your order of inclusion.
But overall it's a fantastic feature. When in doubt initialize with inline static and break the I need a c++ file to initialize a static variable pattern.
Static members of class are compiled as global variable of class scope. How are compiled const static members, and static constexpr members?
Does compiler for every .o file makes copy of this static member or it's done otherwise?
This is covered by C++14 [class.static.data]/5:
Static data members of a class in namespace scope have external linkage. A local class shall not have static data members.
"A class in namespace scope" means classes that aren't at block scope (aka. "local class"). For example this code:
void func()
{
class C { static const int x = 5; };
}
is ill-formed.
To answer your question:
Does compiler for every .o file makes copy of this static member or it's done otherwise?
Typically, if the static member has a definition outside of the class there will be one copy of it, in the object file corresponding to the location of that definition, otherwise there will be none.
Why static variable in a class has to be re-initialised as a global in the file?
Otherwise, it gives a linking error. What is the theory behind it? I understand that the static variable will be in the Data Segment.
my_class.h
class my_class
{
public:
static int m_fid;
void get_fid();
};
my_class.cpp:
#include <iostream>
using namespace std;
int main()
{
my_class t;
/**this gives a linking error */
my_class::m_fid = 0;
return 0;
}
First of all the definition of static variable is wrong.
Instead of my_class::m_fid = 0; you should define as int my_class::m_fid = 0; when you do that there will be no more linker error..
Another thing as per standard...
The definition for a static data member shall appear in a namespace
scope enclosing the member’s class definition.
Yes, static variables (wherever they are declared) go into the data segment.
static means different things depending where it's used, though.
At file or namespace scope, it means the variable is specific to the .cpp file (translation unit).
At local scope, it means the variable is specific to that scope, which may be specific to the translation unit, or shared between translation units if it's in an inline function.
At class scope, a static member declaration inside the class is effectively (almost) the same as one outside the class with the extern specifier.
Like a variable declared extern, a static member is only considered to be declared (and not defined) until a definition is reached.
There is an exception for some static const and static constexpr members, that they may be initialized inside the class and then immediately used, subject to the restriction that the address of the member is never used.
I have this problem with a static functions declared in a header file.
Say I have this file "test.cpp":
#include <cstdlib>
#include "funcs.hpp"
...do some operations...
void *ptr = my_malloc(size);
...do some operations...
The "funcs.hpp" file contains:
#include <ctime>
#include "../my_allocator.hpp" // my_malloc is defined here as a
// global static function
...some functions...
static int do_operation() {
// variables declaration
void *p = my_malloc(size);
// ...other operations
}
when I compile my program, I get an error 'my_malloc' was not declared in this scope, referred to the one used in the "funcs.hpp" file, while it doesn't complain with the one used in "test.cpp".
The function in question is defined as a global static function within the header "my_allocator.hpp", and all it does is to get an instance of the allocator object and use the malloc function:
static void * my_malloc(size_t size) {
return MYAllocator::instance()->malloc(size);
}
I'm not sure whether this problem is related to the scope of a function declared as static global inside a header, but what looks weird to me is that it complains in one case and not in the other: when I use it in a static function in a header (funcs.hpp) that includes the header where it is declared, it results in the error "not declared in this scope"; while it is OK when used from a file that includes the header "funcs.hpp".
Where am I getting wrong?
The static specifier specifies that the symbol (variable or function) will be visible only in this translation unit. I think thats not the case you want, so remove the static specifier.
Note what the compiler is saying: "my_malloc was not declared in this scope". Thats exactly what you specified with static: Internal linkage
Also note that this use of the static keyword was deprecated in favor of unnamed namespaces.
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.