static const array initialized in the .cpp file - c++

I have a problem with a part of old C++ code.
In the header file of the class myClass there is a static array member defined as follow:
static const int myArray[];
In the .cpp file it is initialized as follow:
const int myClass::myArray[]={2,4,5,7,9,11,13};
Is that allowed?
I don't care if it is not nice for the moment, I just want to know if it is going to give me weird problems..

Is that allowed?
To repeat #bolovs comment:
Yes, it's perfectly ok
I'm not fully sure what especially OP worried about.
So, I list the suspected issues the OP may have seen.
1. declaration in .h vs. definition in .cpp
That was the usual (and only) way to define static member variables in C++ – before static inline member variables were invented in C++17.
As a header might be included into more than one translation unit (aka. .cpp file), a definition in the header would be processed by the compiler multiple times and, hence, violate the One Definition Rule and usually result in a linker error.
2. declaration with empty brackets in .h
For the declaration, the actual size of the array is not necessary.
Please, note: static member variables does not contribute to the size of the class.
Hence, when the class is used in other translation units then the unknown size of the array is nothing that hinders the compiler to determine the correct size of the class.
3. definition with empty brackets in .cpp
This is an ancient feature which was inherited from C: An array may be defined leaving the size out when it can be determined from the initializer.
This is useful to eliminate redundancy from code.
(Otherwise, annoying bugs like const char text[10] = "Hello world."; may result because the author was not able to count correctly that "Hello world." requires 13 elements but not 10.)

Related

Sudden NULL value in C++ object [duplicate]

I would like to make an array of integers via the malloc method. I want this array to be global and be used anywhere in my program. I put code in a header file that looked like this:
static int *pieces;
Then I have a function that fills it with numbers that I want in there. The function is in a namespace and the namespace is implemented in its own .cpp file. However, I import the header file into main.c and call the function from the namespace that creates the array like:
pieces = malloc(sizeof(int) * 128);
But when I try to access numbers in the array in main (after calling the function that creates my array), it crashes and says that pieces wasn't initialized. But in the function I have I can create it and manipulate the numbers in it just fine. I was under the impression that by making pieces a static variable, whenever some function anywhere changes (or sets it) then that will affect the usage of the variable anywhere. Basically what I'm trying to say is why does pieces appear unset in main, even though I set it in a function that I called?
Static is a keyword with many meanings, and in this particular case, it means not global (paraphrasing)
It means that each .cpp file has its own copy of the variable. Thus, when you initialize in main.cpp, it is initialized ONLY in main.cpp. The other files have it still uninitialized.
First thing to fix this would be to remove the keyword static. That would cause the "Multiple definitions issue". To fix this you should define the variable in a .cpp file and just extern declare it in a header file.
Edit: You are just allocating memory to it, doesnt count as initialization. You need to initialize the memory to 0 after allocation.
You can use new int[128]() instead of your more verbose malloc syntax, and this would perform initialization as well? Or you could take the easy road (thats what its there for) and use std::vector
The key is this:
static int *pieces;
You said you put that in your header. This is not the way to export a symbol. Any file that includes the header will get its own static version of an uninitialised pointer called pieces.
Instead, you put this in your header:
extern int *pieces;
extern int init_pieces();
And in the source file, you do this:
static const size_t num_pieces = 128;
int *pieces = 0;
int init_pieces()
{
pieces = malloc( num_pieces * sizeof(int) );
return pieces != NULL;
}
Now when you include your header, your source file will know to get pieces from somewhere else, and will wait for the linker to work out where. I also suggested an 'init' function for the array. I did not put a 'release' function in, however.
Note this is all C, not C++. If you're using C++ you should really use new or better still, use a vector.
Also, when using statics in C++, be mindful of this: C++ static initialization order
In C++17 standard, you can use inline specifier instead of static. For variables this means every object unit will have a copy of the variable, but linker will choose only one of them.
Or, as stated on cppreference:
An inline function or inline variable (since C++17) has the following
properties:
1) There may be more than one definition of an inline
function or variable (since C++17) in the program as long as each
definition appears in a different translation unit and (for non-static
inline functions and variables (since C++17)) all definitions are
identical. For example, an inline function or an inline variable
(since C++17) may be defined in a header file that is #include'd in
multiple source files.
2) The definition of an inline function or
variable (since C++17) must be present in the translation unit where
it is accessed (not necessarily before the point of access).
3) An inline function or variable (since C++17) with external linkage (e.g.
not declared static) has the following additional properties:
1) It must be declared inline in every translation unit.
2) It has the same address in every translation unit.
Supported in (source):
MSVC since version 19.12 (VS 2017 15.5)
GCC 7
Clang 3.9
ICC 18.0
In this case, it means you can replace
static int *pieces;
with
inline int *pieces;
For high performance code on various architectures, you may want a malloc-y allocation rather than generic new. That is because you would wrap it with something like mymalloc() and then use architecture dependent functions, such as ones that implement the proper alignment to avoid cache misses and do other nifty things provided by the hardware manufacturer, such as IBM (Bluegene) or Intel (MIC). All of these optimized allocation routines have the malloc type framework.

Static global variables in C++

I would like to make an array of integers via the malloc method. I want this array to be global and be used anywhere in my program. I put code in a header file that looked like this:
static int *pieces;
Then I have a function that fills it with numbers that I want in there. The function is in a namespace and the namespace is implemented in its own .cpp file. However, I import the header file into main.c and call the function from the namespace that creates the array like:
pieces = malloc(sizeof(int) * 128);
But when I try to access numbers in the array in main (after calling the function that creates my array), it crashes and says that pieces wasn't initialized. But in the function I have I can create it and manipulate the numbers in it just fine. I was under the impression that by making pieces a static variable, whenever some function anywhere changes (or sets it) then that will affect the usage of the variable anywhere. Basically what I'm trying to say is why does pieces appear unset in main, even though I set it in a function that I called?
Static is a keyword with many meanings, and in this particular case, it means not global (paraphrasing)
It means that each .cpp file has its own copy of the variable. Thus, when you initialize in main.cpp, it is initialized ONLY in main.cpp. The other files have it still uninitialized.
First thing to fix this would be to remove the keyword static. That would cause the "Multiple definitions issue". To fix this you should define the variable in a .cpp file and just extern declare it in a header file.
Edit: You are just allocating memory to it, doesnt count as initialization. You need to initialize the memory to 0 after allocation.
You can use new int[128]() instead of your more verbose malloc syntax, and this would perform initialization as well? Or you could take the easy road (thats what its there for) and use std::vector
The key is this:
static int *pieces;
You said you put that in your header. This is not the way to export a symbol. Any file that includes the header will get its own static version of an uninitialised pointer called pieces.
Instead, you put this in your header:
extern int *pieces;
extern int init_pieces();
And in the source file, you do this:
static const size_t num_pieces = 128;
int *pieces = 0;
int init_pieces()
{
pieces = malloc( num_pieces * sizeof(int) );
return pieces != NULL;
}
Now when you include your header, your source file will know to get pieces from somewhere else, and will wait for the linker to work out where. I also suggested an 'init' function for the array. I did not put a 'release' function in, however.
Note this is all C, not C++. If you're using C++ you should really use new or better still, use a vector.
Also, when using statics in C++, be mindful of this: C++ static initialization order
In C++17 standard, you can use inline specifier instead of static. For variables this means every object unit will have a copy of the variable, but linker will choose only one of them.
Or, as stated on cppreference:
An inline function or inline variable (since C++17) has the following
properties:
1) There may be more than one definition of an inline
function or variable (since C++17) in the program as long as each
definition appears in a different translation unit and (for non-static
inline functions and variables (since C++17)) all definitions are
identical. For example, an inline function or an inline variable
(since C++17) may be defined in a header file that is #include'd in
multiple source files.
2) The definition of an inline function or
variable (since C++17) must be present in the translation unit where
it is accessed (not necessarily before the point of access).
3) An inline function or variable (since C++17) with external linkage (e.g.
not declared static) has the following additional properties:
1) It must be declared inline in every translation unit.
2) It has the same address in every translation unit.
Supported in (source):
MSVC since version 19.12 (VS 2017 15.5)
GCC 7
Clang 3.9
ICC 18.0
In this case, it means you can replace
static int *pieces;
with
inline int *pieces;
For high performance code on various architectures, you may want a malloc-y allocation rather than generic new. That is because you would wrap it with something like mymalloc() and then use architecture dependent functions, such as ones that implement the proper alignment to avoid cache misses and do other nifty things provided by the hardware manufacturer, such as IBM (Bluegene) or Intel (MIC). All of these optimized allocation routines have the malloc type framework.

What happens if I implement a class in the header file? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Inline functions in C++
What does the compiler do if I completely implement a class in its header file? A typical example follows:
class MyException
{
public:
explicit MyException(const char* file, int line) file(file), line(line) {};
const char* getFile() const { return file };
int getLine() const { return line };
private:
const char* const file;
const int line;
};
My intention is to use the class like this: throw MyException(__FILE__, __LINE__).
I include this header file into each .cpp file. I suppose the compiler will compile the class as many times as it is defined and include the (identical) machine code into every object file it produces. Now, what will the linker do? I tried a simpler example (without all those pesky const's) and it compiled fine.
What would happen, if instead of a simple class, I implemented a three-screenful-long C function in a header file? And the final question, should I split my example into .h and .cpp files?
All methods will be inline methods. You may loose some minimal time on the overall compilation, but it's ok. As far as I know the only problem that can occur is if you have a static non-cost member variable. Then you have to assign a storage place for it (place a definition and and initial value if you want) presumably in a .cpp or else you will get linker errors about multiple definition.
I've seen header-only projects which had only the main() function in a CPP, but that was heavily templated.
Update for C++17: You can declare static non-const members as inline in your header file since C++17. This makes header-only libraries easily possible without gymnastics like static variables inside inline functions.
A class definition itself doesn't produce any code. It just shows users of the class how it is layed out, so they can generate appropriate code to manipulate it.
It's the member functions of the class that generate code. When you define a member function inside the class definition it gives the function an implicit inline declaration.
A function call can be compiled and linked in one of two ways:
(1) A single copy of the function code with a RETURN assembly instruction at the end can be placed in the image, and a CALL assembly instruction can be placed (along with param passing and return value transfer) at the call site to transfer control to this code.
or
(2) An entire copy of the function implementation can replace the entire function call at the call site.
A function declared inline is a recommendation to the compiler to do it the second way. Further an inline declaration allows the function to be defined in several translation units (so it can be placed in a shared header file). In order for the compiler have the option of implementing the second method, it needs a copy of the function implementation at compile-time. This isn't available if the function implementation is in a foreign translation unit.
It should also be noted that modern compilers do complicated things with functions declared inline. See:
http://gcc.gnu.org/onlinedocs/gcc/Inline.html
When you implement member functions inside a header file, all those functions become implicitly inline.
What does this mean and what implications does it have?
As per,
C++03 Standard §7.1.3/4:
It hints the compiler that substitution of function body at the point of call is preferable over the usual function call mechanism.
Even if the inline substitution is omitted, the other rules(especially w.r.t One Definition Rule) for inline are followed.
So Yes, every translation unit will have the definition of the inline function.This may result in increase in the size of your binaries.
Usually any good mainstream compiler will substitute function body at the point of call if needed, so marking functions inline merely for #1 is not really a good idea but if you want to make your intent clear to users of your class then you can do so by defining the functions within the header or explicitly marking your functions as inline.
Should I split my example into .h and .cpp files?
Yes, that is the usual compilation model that most of the projects use, wherein you separate the interface(.h) from the implementation(.cpp).The interfaces are shared with the users of your code as header files while the implementation is provided in the form of binaries.To some extent this provides a safeguard to your intellectual property.
This is known as the Separation Model.
C++ projects using templates will usually use the Inclusion Model rather than the Separation Model of usual C++ projects.

why do " int ClassName :: VariableName " always needed to complete linkage?

class X {
static int i;
// some other function, variable declaration, cons, dest
};
int X :: i ; **(!)**
Why must I write that (!) line, always ?
If I dont write, compiler cannot complete internal linkage, and so it gives ( I assume ) linker error. Why ?
This is known as the One Definition Rule. Each global object (technically, each object with external linkage) must be defined in exactly one source file (technically, in one translation unit). However, it can be declared as many times as you like.
Typically, a class definition will be in a header file, which might be included by many source files. So any static members can't be defined there, only declared, otherwise there will be multiple definitions. You must separately define the static members in exactly one source file, in order for the linker to find exactly one definition. That is what the line marked (!) does.
Because that is how static members work. They exist apart from the instances directly in the class.
You can't define them inside the class, because then you would have multiple definitions for every implementation file that is using your class.
Therefore you need to choose one implementation file that will actually define the static member.
The static variable must be defined (as opposed to declared) in a TU (i.e. a cpp file).
If it's only declared and not defined, no storage is allocated for it, so the linker can't find it.
static int i; is a declaration, i.e. tells to the compiler that in some translation unit (=>.cpp file) such static field will be actually defined. It is needed to let the compiler know that such variable exists and to let you use it in each translation unit where it's declared.
int X :: i;, instead, is a definition, it tells to the compiler to actually provide the space for that variable. It must stay in a single .cpp, otherwise each translation unit would provide some space for it on its own (and the linker would complain).
It's the exact same reason why for globals you need an extern declaration in every file that needs to use it (usually put in a header) and a normal definition in the single .cpp that defines it.
C++ makes a clear distinction between declaration and definition. You need to tell the compiler two things:
The data type of the variable: declaration.
The place in memory on where you want your variable to be located: definition.
This is usually done in one single step, ie a local int variable:
void f() {
int x; // Declaration and definition.
}
Since a .hpp header file can be included on many .cpp files, your (!) line must reside on a single specific .cpp, usually outside any header file.
Static class members are shared among all class instances (there is one and only place in memory where such variable resides) and therefore static int i; inside class declaration represents variable declaration only - and you need to allocate memory for that variable somewhere - you need to define it - which is done in implementation file with int X::i;
The class definition only defines the member, but it must exist in a single compilation unit (i.e. a .cpp file).
You could say it is part of the "one-definition rule".

Header Guards and LNK4006

I have a character array defined in a header
//header.h
const char* temp[] = {"JeffSter"};
The header if #defined guarded and has a #pragma once at the top. If this header is included in multiple places, I get an LNK4006 - char const * * temp already defined in blahblah.obj. So, I have a couple of questions about this
Why does this happen if I have the guards in place? I thought that they prevented the header from being read in after the first access.
Why do the numerous enums in this header not also give the LNK4006 warnings?
If I add static before the signature, I don't get the warning. What are the implications of doing it this way.
Is there a better way to do this that avoids the error, but lets me declare the array in the header. I would really hate to have a cpp file just for an array definition.
Why does this happen if I have the guards in place? I thought that they prevented the header from being read in after the first access.
Include guards make sure that a header is included only once in one file (translation unit). For multiple files including the header, you want the header to be included in each file.
By defining, as opposed to declaring variables with external linkage (global variables) in your header file, you can only include the header in once source file. If you include the header in multiple source files, there will be multiple definitions of a variable, which is not allowed in C++.
So, as you have found out, it is a bad idea to define variables in a header file for precisely the reason above.
Why do the numerous enums in this header not also give the LNK4006 warnings?
Because, they don't define "global variables", they're only declarations about types, etc. They don't reserve any storage.
If I add static before the signature, I don't get the warning. What are the implications of doing it this way.
When you make a variable static, it has static scope. The object is not visible outside of the translation unit (file) in which it is defined. So, in simple terms, if you have:
static int i;
in your header, each source file in which you include the header will get a separate int variable i, which is invisible outside of the source file. This is known as internal linkage.
Is there a better way to do this that avoids the error, but lets me declare the array in the header. I would really hate to have a cpp file just for an array definition.
If you want the array to be one object visible from all your C++ files, you should do:
extern int array[SIZE];
in your header file, and then include the header file in all the C++ source files that need the variable array. In one of the source (.cpp) files, you need to define array:
int array[SIZE];
You should include the header in the above source file as well, to allow for catching mistakes due to a difference in the header and the source file.
Basically, extern tells the compiler that "array is defined somewhere, and has the type int, and size SIZE". Then, you actually define array only once. At link stage, everything resolves nicely.
Include guards protect you from including the same header into the same file repeatedly - but not from including it in distinct files.
What happens is that the linker sees temp in more then one object file - you can solve that by making temp static or putting it into an unnamed namespace:
static const char* temp1[] = {"JeffSter"};
// or
namespace {
const char* temp2[] = {"JeffSter"};
}
Alternatively you can use one source file which defines temp and just declare it as extern in the header:
// temp.cpp:
const char* temp[] = {"JeffSter"};
// header.h:
extern const char* temp[];
Header guards have absolutely nothing to do with preventing multiple definitions in your entire program. The purpose of header guards is to prevent multiple inclusion of the same header file into the same translation unit (.cpp file). In other words, they exist to prevent multiple definitions in the same source file. And they do work as intended in your case.
The rule that governs multiple-definition issues in C++ is called One Definition Rule (ODR). ODR is defined differently for different kinds of entities. For example, types are allowed to have multiple identical definitions in the program. They can (and most always have to) be defined in every translation unit where they are used. This is why your enum definition does not result in an error.
Objects with external linkage are a completely different story. They have to be defined in one and only one translation unit. This is why your definition of temp causes an error when you include the header file into multiple translation units. Include guards can't prevent this error. Just don't define objects with external linkage in header files.
By adding static you give your object internal linkage. This will make the error disappear, since now it is perfectly OK from ODR point of view. But this will define an independent temp object in each translation unit into which your header file is included. To achieve the same effect you could also do
const char* const temp[] = { "JeffSter" };
since const objects in C++ have internal linkage by default.
This depends on whether you need an object with external linkage (i.e. one for the entire program) or an object with internal linkage (unique to each translation unit). If you need the latter, use static and/or extra const (if that works for you) as shown above.
If you need the former (external linkage), you should put a non-defining declaration into the header file
extern const char* temp[];
and move the definition into one and only one .cpp file
char* const temp[] = { "JeffSter" };
The above declaration in the header file will work for most purposes. However, it declares temp as an array of unknown size - an incomplete type. If you wish to declare it as an array of known size, you have to specify the size manually
extern const char* temp[1];
and remember to keep it in-synch between the declaration and definition.
I respectfully disagree with the advice against defining variables in headers, because I think "never" is too broad. Nevertheless, the episode that brought me to this thread offers a cautionary tale for those who dare to do so.
I landed on this page as the result of an inquiry into the cause of warning LNK4006, calling out a long established array that I just moved from the translation unit that defines my DLLMain routine into the private header that is included in most of the translation units that comprise this library. I have compiled this library hundreds of times over the last 11 years, and I had never before seen this warning.
Shortly after I read this page, I discovered the cause of the error, which was that the definition was outside the guard block that protects everything else that is defined in the module that also defines DLLMain, which is where I usually gather all the memory blocks that need external linkage. As expected, moving the table inside the guard block eliminated the warnings, leaving me with only two, related to a brand new externally linked table, to be resolved.
Takeaway: You can define variables in headers, and it's a great place to put common blocks, but mind your guards.
Hang on... you are mixing up your declarations...you did say 'char const * * temp' yet in your header file you have 'const char* temp[] = {"JeffSter"};'.
See section 6.1 of the C FAQ, under 'Section 6. Arrays and Pointers', to quote:
6.1: I had the definition char a[6] in one source file, and in
another I declared extern char *a. Why didn't it work?
A: In one source file you defined an array of characters and in the
other you declared a pointer to characters. The declaration
extern char *a simply does not match the actual definition.
The type pointer-to-type-T is not the same as array-of-type-T.
Use extern char a[].
References: ISO Sec. 6.5.4.2; CT&P Sec. 3.3 pp. 33-4, Sec. 4.5
pp. 64-5.
That is the source of the problem. Match up your declaration and definitions. Sorry if this sounds blunt, but I could not help noticing what the linker was telling you...