Understanding static initialization - c++

I wrote this code:
#include <cstdlib>
#include <iostream>
#include <stdio.h>
constexpr int foo(int a, int b)
{
return a*b;
}
int bar(int a, int b)
{
return a*b;
}
int a = bar(1,2); // Dynamic initialization. This brace-or-equal initializer
// contains expression which is not a constant expression
int main()
{
a = foo(3,4); // Constexpr function invocation. Static initialization.
std::cout << a; // 12
}
This program outputs 12. I expected that 2 will be outputted. Because every Static Initialization is performed before Dynamic Initialization. I'm confused.

Assignment is not initialisation. The assignment from foo(3,4) happens after main begins (which is after the initialisation from bar(1,2)), and before printing the value.

a is not declared constexpr so it cannot be initialized via a constexpr expression. In the scenario you present, the second "initialization" is in fact a dynamic assignment.

Related

Why this constexpr expression gives me an error?

In the code below, constexpr for the line 2 does not give an error, but line 1 does.
#include <iostream>
using namespace std;
class ComplexNum{
public:constexpr ComplexNum(int _r=0,int _i=0):r(_r),i(_i){}
private:
int r,i;
};
int randGen(){
return 10;
}
constexpr int numGen(int i,int j){
return i+j;
}
int main()
{
constexpr int i=10,j=20;
constexpr ComplexNum c3(randGen(),randGen()); //line 1
constexpr ComplexNum c4(numGen(i,j),numGen(i,j));//line 2
return 0;
}
From the knowledge I have, constexpr evaluates the expression at compile time.
Then, shouldn't the compiler be able to evaluate the expression in line 1, because it returns a constant integer (10 in this case)?. If not, how will line 2 be okay?
The compiler can't compile line one because randGen() is not constexpr. The compiler can't magically tell if a function is constexpr. Maybe it looks constexpr, but you actually want it to run at runtime. For that reason, the compiler doesn't evaluate expressions which are not marked constexpr explicitly. Do this:
#include <iostream>
using namespace std;
class ComplexNum{
public:constexpr ComplexNum(int _r=0,int _i=0):r(_r),i(_i){}
private:
int r,i;
};
constexpr int randGen(){
return 10;
}
constexpr int numGen(int i,int j){
return i+j;
}
int main()
{
constexpr int i=10,j=20;
constexpr ComplexNum c3(randGen(),randGen()); //line 1
constexpr ComplexNum c4(numGen(i,j),numGen(i,j));//line 2
return 0;
}

Passing global variables as const reference

The following code compiles and works. The value displayed of both a and n are 4.
#include <iostream>
using namespace std;
int a = 2;
void foo(int const&n)
{
a = n*2;
cout<<"a = "<<a<<" n = "<<n<<endl;
}
int main()
{
foo(a);
}
OUTPUT: a = 4 n = 4
Why does the compiler not complain about n being a const reference? For example, the following code fails to compile.
#include <iostream>
using namespace std;
int a = 2;
void foo(int const&a)
{
a = a*2;
cout<<"a = "<<a<<endl;
}
int main()
{
foo(a);
}
OUTPUT: In function 'void foo(const int&)':
10:7: error: assignment of read-only reference 'a'
How are the two cases different ?
In the first case you're assigning to a global variable a. n changes because it's a reference to the mutable global variable. Changing a is allowed, but changing n directly is forbidden.
In the second case you're trying to re-assign to the const argument a. This is forbidden as a is const.
What you've done is shadow global variable a with a local variable. In the second example, within foo the global variable named a does not exist, instead there's an argument that occupies that name.

I compiled this seemingly incorrect code, but I don’t understand why

I am learning C++ on a linux machine. I just tried “int i();” to declare a function but I forgot to define it. But to my surprise, this code can be compiled and output 1. I feel very confused. I tried “int I{};”, it still compiled with no errors. Please help to explain. Thanks in advance.
//test1.cpp
#include <iostream>
int main(void)
{
int i{};
std::cout << i << std::endl;
return 0;
}
g++ test1.cpp
./a.out
Output is: 0
//test2.cpp
#include <iostream>
int main(void)
{
int i();
std::cout << i << std::endl;
return 0;
}
g++ test2.cpp
./a.out
Output is : 1
In your first example, you define a variable named i, and value-initialise it, which for int means zero-initialisation.
int i{}; // defines i, initialised to zero
In your second example, you declare a function named i, which takes no parameters, and return int:
int i(); // declares a function
When you print this:
std::cout << i << std::endl;
i first get converted to bool (i decays to a function non-nullptr pointer, then it becomes true), and then printed as an integer, that's why you get 1. The compiler can make this conversion without the definition of i (as the result is always true), that's why you got no linker error.
If your intent was to call this function, and print the result, you'll need to use i():
std::cout << i() << std::endl;
This, of course, needs i's definition.
In your code:
//test1.cpp
#include <iostream>
int main(void)
{
int i{};
std::cout << i << std::endl;
return 0;
}
You are not actually declaring a function without defining it. The line of code int i{}; within the main() function here is a variable of type int named i and you are using a brace initializer list to initialize the variable i with out any values and in most cases could be 0 but can vary by compiler.
//test2.cpp
#include <iostream>
int main(void)
{
int i();
std::cout << i << std::endl;
return 0;
}
In this situation it is basically the same thing. You are within main() and by the rules of the language "you can not declare-define a function within a function", so this results in a declaration - definition of a variable. The only difference here is you are not using a brace initializer list here you are using it's ctor constructor called value initialization. Again you are not passing any values to it and in your case it's assigning an arbitrary value of 1.
Now if your code looked like this:
#include <iostream>
int i();
int main() {
std::cout << i() << '\n';
return 0;
}
This would fail to compile because the function i is declared but not defined. However if you did this:
#include <iostream>
// The text in quotes is not meant to be a string literal. It
// is the message of the text that represents any integer X.
int i() { return /*"some int value"*/ 1; }
int main() {
std::cout << i() << '\n';
return 0;
}
This would compile and run perfectly fine because the function i is both declared and defined.

If the original variable is missing from the class containing the referenced member, why is it still accessible?

A member of a class is a reference to a local variable. When the local variable is destructed, and the object of this class still exists, you can access the destructed local variable through this object. Why?
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class c2
{
public:
int& a;
c2(int & c):a(c)
{
}
};
int main()
{
c2 * p;
{
int i = 20;
p = new c2(i);
}
cout << p->a;
system("pause");
return 0;
}
As pointed out by some comments above, the behavior is actually undefined. See in particular the c++ reference on the Lifetime of a temporary:
a temporary bound to a reference in the initializer used in a
new-expression exists until the end of the full expression containing
that new-expression, not as long as the initialized object. If the
initialized object outlives the full expression, its reference member
becomes a dangling reference.
If you use gcc or clang you can compile the program with the option -fsanitize=address: it will crash with
ERROR: AddressSanitizer: stack-use-after-scope
Instead, you will not get any error if you modify your program as follows:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class c2
{
public:
int& a;
c2(int & c):a(c)
{
}
};
int main()
{
c2 * p;
{
int i = 20;
p = new c2(i);
cout << p->a;
}
delete p;
return 0;
}
(In the program I have inserted a delete p to avoid memory leak)

Confusion about inline function

I have a question regarding inline function.
#include <iostream>
using namespace std;
class A
{
public:
inline void fun()
{
int i=5;
cout<<i<<endl;
}
};
int main()
{
A a1;
int i = 2;
a1.fun();
cout<<i<<endl;
return 0;
}
In above program, when function fun() was called, the compiler should have made copy of this function and insert into main function body because it is inline.
So, I have a question, Why doesn't compiler give an error of variable int i; being re-declared?
You seem confused about scopes. They're not "within the same" scope
You can declare multiple variables with the same name at different scopes. A very simple example would be the following:
int main()
{
int a; // 'a' refers to the int until it is shadowed or its block ends
{
float a; // 'a' refers to the float until the end of this block
} // 'a' now refers to the int again
}
Inline expansion is not pure text replacement (as opposed to macros).
Whether a function is inlined or not has no effect on semantics Otherwise the program would behave differently depending on whether the function was inlined or not, and return statements would not behave properly at all.