If you want to wrap some enum type with a class, e.g., to build some functions around it, you could end up with the following situation:
main.cpp:
#include "WrappedEnumConstants.h"
int main(int argc, char * argv[])
{
WrappedZero.print();
WrappedOne.print();
}
WrappedEnumConstants.h
#ifndef WRAPEDENUMCONSTANTS_H
#define WRAPEDENUMCONSTANTS_H
#include "WrappedEnum.h"
#include "InternalEnum.h"
static const WrappedEnum WrappedZero(ZeroEnum);
static const WrappedEnum WrappedOne(OneEnum);
#endif
WrappedEnum.h
#ifndef WRAPPEDENUM_H
#define WRAPPEDENUM_H
#include <iostream>
#include "InternalEnum.h"
class WrappedEnum
{
public:
WrappedEnum(InternalEnum a);
void print() const;
private:
InternalEnum a;
};
#endif
WrappedEnum.cpp
#include <iostream>
#include "WrappedEnum.h"
WrappedEnum::WrappedEnum(InternalEnum a) :
a(a)
{}
void WrappedEnum::print() const {
std::cout << "WrappedEnum: " << a << std::endl;
}
InternalEnum.h
#ifndef INTERNALENUM_H
#define INTERNALENUM_H
enum InternalEnum { ZeroEnum, OneEnum};
#endif
The output I get is like expected:
WrappedEnum: 0
WrappedEnum: 1
I am wondering if initialization of the static constants WrappedZero and WrappedOne is safe. Are the constants of ZeroEnum and OneEnum guaranteed to be initialized before WrappedZero and WrappedOne or was I only lucky? Especially, I am wondering what pitfalls there might be if you used the WrappedEnum in a large project with many things linked together. Do you see any?
Are there differences in initialization of enum constants (like ZeroEnum and OneEnum) and a global "static const int"?
Are the constants of ZeroEnum and OneEnum guaranteed to be initialized before WrappedZero and WrappedOne or was I only lucky?
They are compile-time constants, so are not initialised at runtime at all. It's safe to use them at any time.
Are there differences in initialization of enum constants (like ZeroEnum and OneEnum) and a global "static const int"?
If the static const int is initialised with a constant value, it will be a compile-time constant in any code that knows its value. Otherwise, it will be initialised during the static initialisation phase, before the program starts. In either case, it's also safe to use it at any time.
If it needs to be initialised with a run-time value, then it will be initialised during the dynamic initialisation phase (like your "wrapped" objects), and you may encounter problems with the initialisation order.
Yes there is a difference.
A field of enum type in an instance is for the compiler unknown at compile time so when generating code it's forced to actually access the instance to find the value and the generated code will be bigger and slower.
A const int can instead be known at compile time (if you initialize it with a constant) and so the compiler can generate code that uses directly the value (and you can also use that as a constant expression for example in array declarations or templates).
Also note that wrapping your values in static-duration instances you're creating problems for who will use those wrapped values during the initialization of other static duration instances because the order of initialization is not guaranteed.
I'm not really sure why you think it's a good idea to wrap a box that contains what you need in a bag. Except writing a lot more code and annoying the compiler and your users, what good thing are you achieving doing that?
Related
This question already has answers here:
Sell me const-correctness
(16 answers)
Closed 2 years ago.
What is the point of using the keyword const? for example when making a game, one of the first things to do is to set the width and height of it. And most of the time you'll use for example:
const int Width
and
const int height
Now I know that you should do it like that because the width and height of the screen will not change throughout the game, but what is the point of doing so ? you can do the same thing without using const and it will work just fine.
That was just an example. so what I'm confused about right now is:
What is the point of using the const keyword anywhere if you won't change the variable anyway?
Non-exhaustive list of reasons:
Software Engineering (SWE). SWE is not just programming, but programming with other people and over time.
const allows to explicitly express an invariant, which lets you and others reason about the code. As the program becomes bigger, these invariants cannot be just memorized. That's why encoding them in the programming language helps.
Optimization opportunities.
With the knowledge that certain values will not change, the compiler can make optimizations that would not be possible otherwise. To take this to the max, constexpr means that a value will be known at compile time, not just at run-time. This becomes even more important in potentially multi-threading contexts.
Example:
What kind of optimization does const offer in C/C++?
I leave out whole program analysis which would require a much longer answer and almost certainly is not applicable to generic C++ programs. But whole-program-analysis will allow reasoning of the analyzer or compiler about constness of variables as they get passed between functions, translation units and libraries.
Without const, you have to remember to not change the variable. The larger your program becomes, the harder it gets.
It also has some other useful effects:
const int a = 10;
int b[a]; // Doesn't work if `a` is not `const`.
// ...
void foo(const int &a) {};
void bar()
{
foo(42); // Doesn't work if the parameter is a non-const reference.
}
Having something declared const, compared to a value set with #define for instance, allows you to declare something that the compiler will never let you alter, but that will still keep all of the other properties of a regular variable.
In particular, it will keep a certain place in memory and a pointer on it can be obtained with « & », keeping all read-only routines that use to work on regular object compatible with it.
It's especially useful when your constant object is not a simple native type variable, but rather a complicated object spawned from a class and that still need to be initialized through a constructor.
Also remember that const is a type qualifier, than can apply not only on variable declarations, but also on arguments of a function prototype. In this particular case, this will enable your function to accept both constant or variable arguments.
Such a constant argument could be, for example, a double-quoted "string", which is const char *-typed, because the string is directly part of the code itself and defined at compilation type. Without a const qualifier, nothing could prevent your function from trying to write in it, nor warn the programmer that it's forbidden.
To stay with your example, suppose I write a game library that has a
struct game {
int width;
int height;
int area;
game(int w, int h) : width(w),height(h),area(w*h) {}
};
Now you use my library and because I did not write any documentation (evil me) you just start writing code and try what you can do with that class. You write code
#include <iostream>
int main() {
game g{3,5};
g.width = 12;
std::cout << g.width << " * " << g.height << " == " << g.area;
}
and get output:
12 * 5 == 15
You will complain that the code I wrote is broken because you get non-sense results when you use it. If however I had used const for things you are not supposed to modify:
struct game {
const int width;
const int height;
const int area;
game(int w, int h) : width(w),height(h),area(w*h) {}
};
Then you would get a nice error message that tells you that you tried to modify something that you are not supposed to modify:
prog.cc: In function 'int main()':
prog.cc:11:15: error: assignment of read-only member 'game::width'
g.width = 12;
Once you fixed your code to
#include <iostream>
int main() {
game g{3,5};
std::cout << g.width << " * " << g.height << " == " << g.area;
}
All const could be removed and the output would not change. However this is not always the case. For example member functions can have const and non-const overloads that can do different things depending on whether the method is called on a const or on a non-const object:
#include <iostream>
struct foo {
void sayHello() const {
std::cout << "I am a const object\n";
}
void sayHello() {
std::cout << "I am a non-const object\n";
}
};
int main() {
const foo f;
f.sayHello();
foo g;
g.sayHello();
}
output:
I am a const object
I am a non-const object
Conclusion:
const is mainly to ensure correctnes and to avoid mistakes. const can also be used to make const objects behave differently than non const objects. There is more to it and details you can read up eg here.
const is for a constant variable, that it means nobody should change it, or maybe for const T & passing non-trivial type as parameter, or maybe for making a pointer constant, or for value pointed from the pointer (const *P *variable)
I'm attempting to do the following:
Say I have a class, A, and I have a static member variable, static_bit_id, that is a bitset<128>. At compile time, I want to create an ID that is a one hot bit of my choosing using bitset. I have a function that does this for me onehotbits(int n). for example:
bitset<128> b = onehotbits(4) // 0....01000
At compile time I want to assign to a static member of class A in such a way:
//in A.h
class A{
public:
const static bitset<128> bits;
};
// in A.cpp
const bitset<128> A::bits = onehotbits(1);
Previously this pattern worked with a constexpr function that instead of bitset, took uint64_t's and shifted them. Now doing the same with bitsets violates constexpr rules since operator << for bitset< T > is not a constexpr.
I can't think of a way to accomplish this using constexpr, or in a namespace safe way in general. I can initialize bitset<128> with a string, but that violates constexpr.
I'm currently getting around this problem via:
const bitset<128> A::bits = bitset<128>(1) >> n;
which seems to violate DRIP, the only way to get rid of this problem appears to use a MACRO, which wouldn't be necessary if I could just use >> operator for bitset.
Note I want to avoid using other libraries for this, especially not boost, that is overkill.
Note, while my question is similar to Initializing c++ std::bitset at compile time it is not the same, since the solution there does not work for my problem (since I'm not simply using a literal, but a literal that would have to be created at compile time via some input)
Does this solve your problem?
constexpr auto onehotbits(int i)
{
return 1<<(i-1);
}
class A{
public:
constexpr static std::bitset<128> bits{onehotbits(4)};
};
constexpr std::bitset<128> A::bits;
Calling it via
int main()
{
for(int i=0;i<128;++i)
{
std::cout<<A::bits[i]<<" ";
}
}
yields
0 0 0 1 0 0 0 0 ...
DEMO
With regard to the question whether the shift-operator is constexpr, see here. Didn't get that so far ... if not, the same behavior can attained via a template class.
I've a big file of Constants.h file where about 200 variables(mostly arrays) are declared and initialised. I'm using namespace.
METHOD 1:
//Constants.h
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
namespace LibConstants
{
const int a = 12;
const std::string theme[2]; = {"themeA", "themeB"};
const int arr[2] = {1, 2};
// and around 200 more declarations with initialization
}
#endif
This .h file is #include in almost every .cpp file but each time only very minimal variables are being used like LibConstants::theme[0].
My ways works fine but doesn't it allocate memory unnecessarily?
Shall I follow the approach, to only define variables in .h file and initialize in .cpp?
Like in below code:
METHOD 2:
//Constants.h
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
namespace LibConstants {
std::string getMyTheme(int arg);
std::string getMyThemeName(int arg);
const int a;
const std::string theme[2];
const int arr[2];
// and around 200 more declarations with initialisation
};
#endif
Initialising in cpp file
//Constants.cpp
#include LibConstants.h
using namespace LibConstants {
std::string getMyTheme(int arg) {
theme[2] = {"themeA", "themeB"};
return theme[arg];
}
std::string getMyThemeName(int arg) {
...
}
}
Using it like
//HelloWorld.cpp
#include Constants.h
int main() {
//METHOD 1:
std::string a = LibConstants::theme[0]; // arg=0 is dynamic and is being read from localStorage in my case.
//METHOD 2:
std::string a = LibConstants::getMyTheme(0); //Here also arg=0 is dynamic.
...
}
Here, unnecessary allocation of memory for unneeded variables won't happen except for arrays which are declared as const std::string st[2]; in the header file.
Here "arg=0" is run time involvement. Does it matter if some variable is not dependent on run-time but only compile time in which case it will simply replace the value of placeholder in corresponding .cpp file?
Please correct me wherever I am wrong.
Take the std::string example. Consider,
namespace Constants {
const std::string str = "A not very short string";
}
str is a class type, it has a constructor, and it has to allocate memory to store its contents (unless short-string optimization is used in its implementation. Even in that case, it only applies to, well, "short string"). It is declared a namespace scope variable. So the program has to construct this variable at launch. Every program that has this variable declared, will need to allocate memory, and initialize its contents. That is an overhead you probably don't want, depending on how much that will effect your performance.
On the other hand, if you have,
const std::string &str()
{
const static std::string s = "A not very short string";
return s;
}
Now, you have a static local variable. It will be initialized at the first entry of the function. And it will be initialized only once. If str is never called, it will not be initialized at all.
However, note that the string literal "A not very short string" is still going to occupy some memory. Where and how it is store is implementation defined. Usually in the data segments, and the impact is usually minimal.
In contrast to class types. It is preferable to define fundamental types, especially integral types in the header.
For example,
namespace Constants {
constexpr int x = 10;
}
An optimizing compiler will most likely not to store the variable x and its contents 10 at all. Instead, wherever x is used, it will be replaced by 10, and in some cases, coded into the instruction op-code (so called immediate operands). Of course, this is again an implementation detail. And such optimization cannot be relied on with all compilers. And if you take x's address or otherwise ODR used, compiler will be compelled to make room for this variable anyway. But the bottomline is that, it will be very unlikely that you will be worse off by declaring this constants in header than defining it in an external source file.
Q1:
I have recently read book C++ Primer, when I read follow:
To substitute the value for the variable, the compiler has to see the variable’s initializer. When we split a program into multiple files, every file that uses the const must have access to its initializer. In order to see the initializer, the variable must be defined in every file that wants to use the variable’s value.
I have a question: when I use a variable defined in other file, I just use extern to declare is enough, why should I must have access to its initializer, so I have done a test:
in main.cpp, I write below:
#include <iostream>
using namespace std;
extern int test;
int main()
{
cout << test << endl;
return 0;
}
in test.cpp, I write below:
int test = 100;
and by the way, these two files are added in the same projects, or it will not build successful.
When I run them, it print
100
like I expect. But in main.cpp, I don't need to define something like int test = 100 like book said. I don't know who is right.
Q2:
int i = 43;
const int &r = i;
i = 1; //when i changed, r alse changed
I have tested in gcc 4.7 and visual studio 2013, they both get same result,
r changed. Then, what's the point of const? Shouldn't r always be 43?
I think the quote from the book means something like the following
const size_t N = 10;
int main()
{
int a[N];
//...
}
If the constant N is defined in some other module with specifier extern then in the module with main the compiler does not have an access to the value of the constant and as result it is unable to define the array
extern const size_t N;
int main()
{
int a[N]; // error: the value N is unknown
//...
}
By this reason constants have internal linkage that it could be possible to define them in each module where their values are required at compile time.
As for the second question then constant references are used that to prevent modifying the referenced objects using references.
For example if you want that some function would not change your compound object you can declare its parameter as a constant reference to the object.
Also a temporary objects are bound to constant references.
Consider an example
void display_string( const std::string &s )
{
std::cout << s << std::endl;
}
you may call the function using a character array. For example
display_string( "Hello, World" );
The compiler implicitly converts the string literal to a temporary object of type std::string and binds it to the constant reference of the parameter.
If the parameter would not be declared like constant reference as for example
void display_string( std::string &s );
then the compiler would issue an error.
Using a constant reference it is supposed that the client code will not change the referenced object itself.
That is the client code may look at the object but may not touch it by hands.:)
Q1. have access to its initializer means compiler need to known the variable's initializer(definition). You can let compiler achieve that by link main.cpp and test.cpp together. You said that these two files are added in the same projects, so IDE will do that for you.
You can find more on this question.
Q2. Compiler don't allow you to change r's value, because it's a reference to a const variable, but i is an integer variable, so you can change it's value.
This code will not compile:
#ifndef RemoteControl_h
#define RemoteControl_h
#include "Arduino.h"
class RemoteControl
{
public:
RemoteControl();
~RemoteControl();
static void prev_track();
static void next_track();
static void play_pause_track();
static void mute();
static void vol_up();
static void vol_down();
void respond(int code);
void add_code(int code, void (*func)());
private:
boolean active = true;
struct pair {
int _code;
void (*_func)();
};
const int max = 1000;
int database_length = 0;
pair database[max]; //This line doesn't compile unless I use a literal constant instead of "max"
};
#endif
But if I put the section below in the constructor for the class instead it works fine.
const int max = 1000;
int database_length = 0;
pair database[max];
Am I not allowed to declare an array within a class in c++ and use a virtual constant as the length? I am working in arduino if that makes a difference, but I expect that I am not understanding something with the c++ language since this is a standard .h file. Oh and the problem isn't the .cpp file because I completely removed it with the same results: compiles with literal constant length but not virtual constant length.
In C or C++,try using malloc() in stdlib.h, cstdlib for c++. Don't forget free()
const int max = 1000;
struct pair *ptr = malloc(sizeof(pair) * max); // allocated 1000 pairs
free(ptr); // when the amount of memory is not needed anymore
Let me first clear a few things up for you.
In C, a const variable is considered as const-qualified, it is not a compile-time constant value (unlike an integer literal, which is a compile time constant value). So, as per the rules for normal array size specification, you cannot even use a const variable in this case.
In C, we may have the provision to use VLA which enables us to use syntax like pair database[max] even if max is not a const variable but that is again some optional feature of the compiler (as per C11).
In C++, we can use a const variable as the size of array, as in C++, a const variable is a compile time constant.
So, to answer your question:
In C, your code will be ok if your compiler supports VLA. and even if max is not const.
In C++, there is no VLA, but it maybe supported as a gnu extension. If max is const, it will be ok.
The easiest fix is to just take the
const int max = 1000;
out of the class and put it above the class.
Even better would be to ensure that it is a compile-time constant like so:
constexpr int max = 1000;