How to use extern variable correctly? - c++

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.

Related

C++ what is the point of "const" keyword? [duplicate]

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)

Too much declaration and initialization in header file C++

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.

What does the 'extern' keyword does that makes the following code legal?

Why does the following code compile?
when is the 'num' variable getting its value?
#include <stdio.h>
extern int num;
void main()
{
printf("%d", num); //prints 3
}
int num = 3;
Example: Live Code
It works because you've declared num so it can be named in the function's code, and because you've defined it at namespace scope so that it's initialised at static-initialisation time, which is just before main is executed.
In that sense, your program as currently written is largely indistinguishable from the following:
#include <stdio.h>
int num = 3;
void main()
{
printf("%d", num); //prints 3
}
"Where" you initialise the variable isn't particularly relevant, as long as that occurs in time before you try to use it.
By the way, you must make main return int, not void.
In your code,
extern int num;
is called a declaration. OTOH,
int num = 3;
is the definition with explicit initialization. This statement sets the value. This value is decided at the compile time and set just before main() starts it's execution.
That said, void main() should be int main(void), at least to conform to the standard.
extern marks a declaration of a variable that's defined later. The definition, the int num = 3; part, is what actually allocates the memory for the variable and sets it's value (it also doubles as a declaration). C/C++ are declare-before-use, if you didn't do that extern int num; then num wouldn't be declared at the point you use it. You could also of course drop the extern line and move the definition of num up to above main().
There's two things that come into play here. During compile, num has to be declared at a point in the source file before any use. As for when it gets it's value assigned, that comes during program loading. All variables at file scope (outside any functions) like num have their memory allocated and their values if any initialized before main() is called. If they aren't given a value in their definition they may contain anything, so don't make any assumptions about the value of uninitialized variables. You also can't make any assumptions about the order they're initialized in, so don't refer to other file-scope variables when initializing a variable like this.
extern is used with the declaration. It tells the compiler that the thing will be defined elsewhere. It's useful when you have multiple files using the same variable or function. You would put an extern declaration in a header file, and define the shared variable/function in a source file.
If you remove extern from your code you will be defining num twice, which isn't allowed. To get rid of the extern declaration, just put your int num = 3; at the top of your file.

Casting from const int to int in c++

Can we cast a const int into an int in C++ without declaring a new variable?
This option is available in VS but how can it be used in other compilers such as Xcode, code blocks, etc?
const int a = 5 ;
int (a) ++ ;
a is const. You can't legally remove the constness to mutate the variable in any compiler. What you're seeing in VS is that it's letting you create an unnamed temporary and incrementing THAT.
TL;DR: You can change the value of a const variable but you can't guarantee your code will behave as though you did.
There is, of course, a way to do it, but first lets make sure you understand what you're asking to do:
const int a = 5;
This tells the compiler that there is a value, 5, which you want to refer to as "a", for example so you can do:
const int MaxNameLen = 5;
char name[MaxNameLen + 1];
or
const float pi = 3.14;
return pi * radius;
Compiled without optimization, this will probably produce code which injects a variable like any other and uses it as you would expect.
But by calling the variable "const" you've signed a contract with the compiler: Behave as tho this value does not change. So you can do, for example:
int a = 5;
*(static_cast<int*>(&a))++;
But as far as the compiler is concerned, a did not change. It is free to carry on behaving as tho it didn't. So if it loaded it into a register, if it sized something based on it, it is free to just go ahead and assume it can use the value "5" wherever it sees "a". For example:
#include <iostream>
using namespace std;
int main()
{
const int a = 5;
(*const_cast<int*>(&a))++;
std::cout << "a = " << a << std::endl;
}
might print 5 or it might print 6, depends on which compiler, which settings and the context of the code. Variable "a" has an address but you told the compiler it wouldn't change, so it may already have pushed it onto the stack or loaded it into a register.
Where this is going to hurt you worst is in highly optimized because the compiler is going to produce instructions and ordering based on your promise that "a" does not change.

creating reference to a constant variable in C++

compiler says invalid initialization at line 3
I guess creating reference to i, it is telling the compiler that someone wants to change i, I guess this thing came with newer versions of the compilers because i have found this code in most of the books.
int main(){
const int &i=10;
int &j=1;
cout<<j;
return 0;
}
This:
int &j=1;
Is not valid, because you're creating a non-const reference (which would allow you to modify the referent) from a constant value (which cannot be modified, for obvious reasons).
Do this instead:
const int &j=1;
Also, the line that declares i makes no sense. Just delete it.
Besides missing an int in const &i=10; the issue with the next line is that you are creating a reference that is not const (i.e. which allows what it refers to to be changed) and the number 1 is a constant. You'd encounter the same problem with the following code:
const int i = 1;
int &ri = i;
It should be obvious why.