Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does struct attribute declaration and initialization order behaves like this?

I've recently come across this:

#include <iostream>
#include <vector> 
#include <string>
#include <algorithm>  //sort function
#include <functional> //functions utilities
#include <random>     //random numbers generation

using namespace std;
default_random_engine         generator;
uniform_int_distribution<int> distribution(0,9999);
auto randomer = bind(distribution, generator);


struct Test_struct {
    string  ord_as_string;
    int     ord;
    Test_struct() :
      ord(randomer()),
      ord_as_string(to_string(ord))
    {}
};

int main() {
  vector<Test_struct> my_vector;
  for(int i = 0; i < 100;  ++i) my_vector.push_back(Test_struct());
  for(auto& e: my_vector)
    cout << e.ord_as_string << " -> " << e.ord << endl;
}

Which prints the following sequence:

142 -> 0
0 -> 1315
1315 -> 7556
7556 -> 4586
4586 -> 5327
5327 -> 2189
2189 -> 470
470 -> 6788
6788 -> 6792
...

It doesn't make sense since the struct int and string attributes should refer to the same logical number. So I just changed the declaration to:

 struct Test_struct {
    int     ord;
    string  ord_as_string;
    Test_struct() :
      ord(randomer()),
      ord_as_string(to_string(ord))
    {}
};

I thought that it has something to deal with the order of declaration of the struct attributes and it worked:

0 -> 0
1315 -> 1315
7556 -> 7556
4586 -> 4586
5327 -> 5327
2189 -> 2189
470 -> 470
6788 -> 6788
...

So, can someone explain to me why does the reference to ord is kept in the following structs initializations when it is declared after the other attribute but initialized before?

Edit: Ok, members are initialized in the declaration order as said in the comments, then, why was it designed like that? It makes no sense for me.

like image 803
Netwave Avatar asked Jan 28 '23 01:01

Netwave


1 Answers

You are running into undefined behavior. The order of initialization of the members must match the order of declaration.

Since it does not, the behavior you are observing stems from the ord member being uninitialized and coincidentally reusing the same location in memory on every iteration of the loop. This location happens to hold the value you assigned in the iteration before.

You can read up here what the order of initialization is, and why it is that way. To summarize both the link and comments: the destructor has to destroy objects in the reverse order of initialization, and since there can be multiple constructors, there has to be a single source of truth, which is the order of declaration in the class.

like image 54
midor Avatar answered Feb 06 '23 14:02

midor