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.
Related
I have seen in stackoverflow that
//define in .h
inline void fun()
{
static int i; // one instance include in multiple cpp
}
static inline void fun1()
{
static int i; // multiple instance included in multiple cpp
}
I often write signleton in such a pattern
//define in .h
class Singleton
{
static Singleton& Instance()
{
static Singleton s;
return s;
}
private:
int i;
}
a lot of coders write in this way, Can someone explain is it correct, how C++ ensure one instance?
actually in the inline and static inline version, there is no clear cpp declaration to ensure single instance.
The C++ standard does not "ensure" anything.
The C++ standard specifies the observed results, what happens as the result of this declaration
It is up to each C++ compiler to implement this C++ specification in the manner that produces the specified results.
The C++ standard does not specify exactly how the compiler and the linker go about doing this. The low level details that produces these results are not specified or mandated by the C++ standard, in any way. This is entirely up to the compiler and the linker.
Having said that: the common approach is for the compiler to produce an instance of the static object in every compiled .cpp file. It is also tagged in some manner that uniquely identifies it; and indicates that, when linked with other translation units, only one instance of the uniquely-identified object (in all the compiled object files) is produced in the final linked executable.
This is a problem that was inherited from C and you have to go back quite a bit in history. So a long time a ago in a language not quite C++ ...
The inline keyword was just a hint to the compiler that you would like that function to get inlined. Now some compilers just ignored it because nothing said you had to inline functions marked inline. Some compilers addded a fudge factor to their automatic inline heuristic to make it more likely to get inlined. Others always inlined.
This then caused a problems for functions defined in headers because when the function was not actually inlined you ended up with the same function in multiple compilation units and then the linker complained.
Some compilers marked inline functions so that the linker would ignore duplicate definitions. But to be portable you had to mark your functions static inline. That way, even if the function is present in each compilation unit, the function isn't exported and doesn't collide with definitions of the same function in other compilation units. Drawback is that you get multiple copies of the same function, which is a problem when you have local static variables or use the address of the function.
Warp forward to the near present...
Compilers have gotten a lot smarter about inlining automatically and the feature to mark inline function to allow multiple defintions has kind of taken hold and that is the meaning of the inline specifier in C++. Since C++17 this also holds for inline variables, not just functions.
So inline causes the compiler to mark the function (or variable) in the object file for the linker to
Allow multiple definitions without error or warning.
Pick any one of the definitions and replace all the other instances with that one.
All duplicates of the inline function will end up with the same address and any local static variable will end up with a single instance too. All copies become the same object.
PS: using a static local variable for a singleton is imho the best way as it avoids the Static Initialization Order Fiasco as much as can be and is thread safe.
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.)
Learning from this: By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
But if I write this inside MyTools.h:
#ifndef _TOOLSIPLUG_
#define _TOOLSIPLUG_
typedef struct {
double LN20;
} S;
S tool;
#endif // !_TOOLSIPLUG_
and I include MyTools.h 3 times (from 3 different .cpp) it says that tool is already defined (at linker phase). Only if I change in:
extern S tool;
works. Isn't external default?
The declaration S tool; at namespace scope, does declare an extern linkage variable. It also defines it. And that's the problem, since you do that in three different translation units: you're saying to the linker that you have accidentally named three different global variables, of the same type, the same.
One way to achieve the effect you seem to desire, a single global shared variable declared in the header, is to do this:
inline auto tool_instance()
-> S&
{
static S the_tool; // One single instance shared in all units.
return the_tool;
}
static S& tool = tool_instance();
The function-accessing-a-local-static is called a Meyers' singleton, after Scott Meyers.
In C++17 and later you can also just declare an inline variable.
Note that global variables are considered Evil™. Quoting Wikipedia on that issue:
” The use of global variables makes software harder to read and understand. Since any code anywhere in the program can change the value of the variable at any time, understanding the use of the variable may entail understanding a large portion of the program. Global variables make separating code into reusable libraries more difficult. They can lead to problems of naming because a global variable defined in one file may conflict with the same name used for a global variable in another file (thus causing linking to fail). A local variable of the same name can shield the global variable from access, again leading to harder-to-understand code. The setting of a global variable can create side effects that are hard to locate and predict. The use of global variables makes it more difficult to isolate units of code for purposes of unit testing; thus they can directly contribute to lowering the quality of the code.
Disclaimer: code not touched by compiler's hands.
There's a difference between a declaration and a definition. extern int i; is a declaration: it says that there's a variable named i whose type is int, and extern implies that it will be defined somewhere else. int i;, on the other hand, is a definition of the variable i. When you write a definition, it tells the compiler to create that variable. If you have definitions of the same variable in more than one source file, you've got multiple definitions, and the compiler (well, in practice, the linker) should complain. That's why putting the definition S tool; in the header creates problems: each source file that #include's that header ends up defining tool, and the compiler rightly complains.
The difference between a const and a not-const definition is, as you say, that const int i = 3; defines a variable named i that is local to the file being compiled. There's no problem having the same definition in more than one source file, because those guys all have internal linkage, that is, they aren't visible outside the source file. When you don't have the const, for example, with int i = 3;, that also defines a variable named i, but it has external linkage, that it, it's visible outside the source file, and having the same definition in multiple files gives you that error. (technically, it's definitions of the same name that lead to problems; int i = 3; and double i = 3.0; in two different source files still are duplicate definitions).
By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
That statement is still correct in your case.
In your MyTools.h, tool is external.
S tool; // define tool, external scope
In your cpp file, however, the extern keyword merely means that S is defined else where.
extern S tool; // declare tool
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.
I have a header file that has a number of declarations like this:
extern ID3D10Device* device;
I can't make these static because of a problem with multiple translation units, and I can't have them as normal pointers for a similar reason. However when I try to build the program I get unresolved external symbol linker errors. I'm assuming that this is because I'm attempting to use the pointers without defining them first. This is the problem however, as the way you initialise these DirectX objects is by passing the address of the pointers as parameters into specialist methods. - I may be wrong but I am assuming this is the problem as the compiler / linker / whatever can't see the definitions.
All I'm trying to do is have these pointers (for the graphics device, depth buffer etc) visible to multiple classes. How can this be achieved?
You need the pointers to be defined in some translation unit. The linker is complaining because it seems you haven't done that anywhere. You should declare them at file scope as
ID3D10Device* device = NULL;
in the source file where you call the DirectX function that initializes them. Just make sure the declaration is only made in one source file, then the extern statement should be placed in the associated header file which is included by all translation units that need to use these pointers.
When you externally define a variable like this, the compiler is not reserving any memory for that variable until it sees a definition inside a code module itself. So if you are going to be passing these pointers by-reference to a function for initializing their values, they must be defined in a code module somewhere.
You only need to define them in a single code module ... then place the extern declarations inside a header file you include in the rest of your code modules that require access to the pointer variables. That shouldn't create any linker errors due to duplicate definitions.
I can't make these static because of a problem with multiple translation units
If you need a different variable in different TU (translation units), make it static: this way the variable will be specific to each TU.
A declaration of a variable is also definition unless the extern is used.
You must have one (and only one) definition of a variable in the program.
To have a global variable:
Declare it with the extern keyword in some header file.
Include this header in every TU that needs to use the variable. Never declare the variable directly, never bypass the header inclusion.
Define the variable: a declaration without the extern keyword will define the variable in one TU. You need to include the header file in the same TU to guaranty consistency between the extern declaration and the definition.
the way you initialise these DirectX objects is by passing the address
of the pointers as parameters into specialist methods
To solve this part of the problem, you could do something like this (in a .cpp file):
ID3D10Device* device;
struct Foo {
Foo(ID3D10Device **pdevice) { specialist_method(pdevice); }
};
Foo f(&device);
Beware of the "static initialization order fiasco", though -- it's safe to use device from main, or code called from main, because it will definitely be initialized before that code executes. It's not necessarily safe to use it from other initializers executed before main, because the order of initialization of statics in different translation units is unspecified (within a TU, they're initialized in order of either declaration or definition, I forget which). So device might still be a null pointer in that code. Likewise, specialist_method can't necessarily rely on other statics having been initialized.
There are extra tricks you can use if you need to enforce initialization orders, I'd guess that all the common ones are on SO already in other questions.