This question already has answers here:
Initialization Order of Class Data Members
(2 answers)
Closed 3 years ago.
I'm trying to understand member class initialization order but there is one thing that confusing me.
#include <iostream>
class Foo {
int y{7};
public:
Foo()
{
std::cout << "Foo Constructor";
}
explicit Foo(int yy) : y(yy)
{
std::cout << "Foo " << y << std::endl;
}
int gety()
{
std::cout << "Foo::gety() returning ";
return y;
}
};
class Bar {
int x;
public:
Bar()
{
std::cout << "Bar constructor" << std::endl;
}
explicit Bar(int xx) : x(xx)
{
std::cout << "Bar "<< x << std::endl;
}
int getx()
{
std::cout << "Bar::getx() returning ";
return x;
}
};
class Class {
Bar bar;
Foo foo;
public:
Class() : bar(foo.gety()), foo(5)
{
std::cout << "Class()\n";
}
void printxy()
{
std::cout << "Bar.x = " << bar.getx() << " \n" << "Foo.y = " << foo.gety() << std::endl;
}
};
int main(void)
{
Class k;
k.printxy();
return 0;
}
I'm compiling this code with gcc --std=c++11 -Wuninitialized -Wall -pedantic
In Class object there is two members of class Foo and Bar. In initialization list I'm constructing firs bar object by using constructor that takes int as argument. But as i understand foo is not constructed yet because it's second in order on initialization list. So how i don't get any errors when using foo.gety() before it's constructed?
I think C++ is guarantee that any used object is constructed. So when Foo object is constructed? Or this is undefined behavior?
This is link for coliru example: Link
Member variables are initialized in the order they are defined in the class. In your case bar will be initialized before foo (even if you change the order in the constructor initializer list).
What you're doing, using the uninitialized foo object, will lead to undefined behavior. There's no guarantee that a compiler will be able to catch it or even report it.
Related
This question already has answers here:
What's the point of g++ -Wreorder?
(5 answers)
Closed 2 years ago.
I am reading into Scott Meyers book Effective c++. For constructors he recommends initialization of object data in a specific order.
Base class before derived class
Within a class data members initialized in the order which the are declared.
Appearantly not following these rules can lead to obscure behavioral bugs ... However he does'nt give any examples or go into details.
Can you give an example of what kind of bugs can occur?
For example,
struct S
{
int a;
int b;
S() : b(42), a(b + 1) {}
};
leads to undefined behavior:
As contrary as we might expect from constructor,
a is initialized before b (according to member order).
It can confusing to have the wrong order:
struct foo {
int a;
int b;
foo(int x) : b(++x),a(++x) {
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Constructing a foo(1) prints:
a = 1
b = 2
Not a = 2, b = 1 as one might expect from the order of the initializer list. Real problems can occur if initialization of one member depends on another member. This is correct (but not nice):
struct bar {
int a;
int b;
bar() : b(a),a(1){
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Prints:
a = 1
b = 1
And this invokes undefined behavior:
struct broken {
int a;
int b;
broken() : b(1),a(b){
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Can you give an example of what kind of bugs can occur?
class foo
{
int *ptr;
int size;
public:
foo() : size(10), ptr(new int[size]) {}
};
int main()
{
foo f;
}
See the warnings here.
The size is initialized after the ptr is initialized, thus size is actually some random value when new is issued to allocate dynamically.
This question already has answers here:
Is it defined behavior to reference an early member from a later member expression during aggregate initialization?
(4 answers)
Closed 4 years ago.
Is it legal to do the following?
#include <iostream>
struct Foo
{
int bar;
int baz;
};
int main()
{
Foo instance = { 5, instance.bar };
std::cout << instance.baz << std::endl;
}
I think it's not because as far as I know the order of initialization is unspecified and the bar field can be initialized after baz.
Am I right?
https://coliru.stacked-crooked.com/a/ea97713515dd0687
If you liked your conundrum, this is really gonna bake your noodle:
#include <iostream>
struct Foo
{
int bar=0;
int baz=1;
};
const int cool(const Foo& f)
{
std::cout << "Bar: " << f.bar << " Baz: " << f.baz << std::endl;
return f.bar;
}
int main()
{
Foo instance = { 5, cool(instance) };
std::cout << instance.baz << std::endl;
}
What a previous poster correctly quoted: c++ std draft doc
...all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.
This question already has answers here:
Why can I use auto on a private type?
(5 answers)
Closed 9 years ago.
Let's consider the next code:
#include <iostream>
#include "mydemangled.hpp"
using namespace std;
struct A
{
private:
struct B {
int get() const { return 5; }
};
public:
B get() const { return B(); }
};
int main()
{
A a;
A::B b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And the compiler (gcc 4.7.2) yells saying that A::B is private. All right.
So, I change the code:
int main()
{
A a;
cout << demangled(a.get()) << endl;
cout << a.get().get() << endl;
}
and it doesn't yell:
$ ./a.out
A::B
5
Meaning, I can't to create instances of A::B, but I can use it.
So, new change (the key of my question).
int main()
{
A a;
auto b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And output:
$ ./a.out
A::B
5
What is the trouble here, being A::B private (and thus its constructors, copy constructors and so on)?
In general, access controls names or symbols, not the
underlying entities. There are, and always have been, numerous
ways of accessing private members; what you cannot do is use the
name of such a member.
In your examples, you don't use the name, so there is no
problem.
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.
#include <iostream>
class MyClass
{
public:
MyClass() :
mFirst()
{
}
int mFirst;
int mSecond;
};
int main()
{
MyClass mc;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
int a;
std::cout << "a: " << a << std::endl;
return 0;
}
What is the expected output of this program?
I would think only MyClass.mFirst will be initialized to zero. However GCC initializes them all to zero, even with optimizations enabled:
$ g++ -o test -O3 main.cpp
$ ./test
mc.mFirst: 0
mc.mSecond: 0
a: 0
I'd like to know:
How is each value initialized according to the C++ standard?
Why does GCC initialize them all to zero?
Update
According to Erik the values are zero because my stack happens to contain zeroes. I tried forcing the stack to be non-zero using this construct:
int main()
{
// Fill the stack with non-zeroes
{
int a[100];
memset(a, !0, sizeof(a));
}
MyClass mc;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
int a;
std::cout << "a: " << a << std::endl;
return 0;
}
However, the output stays the same:
mc.mFirst: 0
mc.mSecond: 0
a: 0
Can anyone explain why?
Update 2
Ok I figured it out. GCC was probably optimizing away unused variables.
This application shows the expected behavior:
#include <iostream>
struct MyClass
{
MyClass() : mFirst() { }
MyClass(int inFirst, int inSecond) : mFirst(inFirst), mSecond(inSecond) { }
int mFirst;
int mSecond;
};
int main()
{
// Fill the stack with non-zeroes
// Use volatile to prevent GCC optimizations.
{
volatile MyClass mc(1, 2);
volatile int a = 3;
}
{
volatile MyClass mc;
volatile int a;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
std::cout << "a: " << a << std::endl;
}
return 0;
}
Output:
$ g++ -o test main.cpp
$ ./test
mc.mFirst: 0
mc.mSecond: 2
a: 3
They're (EDIT: With "They" i refer to mSecond and a which are not explicitly initialized) not initialized. Your stack happens to contain 0's so that's the values you get.
8.5/9:
If no initializer is specified for an
object, and the object is of (possibly
cv-qualified) non-POD class type (or
array thereof), the object shall be
default-initialized; if the object is
of const-qualified type, the
underlying class type shall have a
user-declared default constructor.
Otherwise, if no initializer is
specified for a nonstatic object, the
object and its subobjects, if any,
have an indeterminate initial
value; if the object or any of its
subobjects are of const-qualified
type, the program is ill-formed.
They are classified as 'undefined' meaning whatever the compiler decides or whatever was in memory at that location at the time of creation. Basically, leaving them uninitialised is leaving it up to chance and you should initialise them. The only reason for not initialising members of a struct that I can think of is if you have a very, very large array and don't want to be calling a constructor many times.