Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 member variable of reference type, different behaviour after vector push_back

I was using somebody else's class which was acting odd when I pushed it into a vector. It involves a member variable which is a reference to another member variable. Here is the smallest self-contained example:

#include <iostream>
#include <vector>

class Myclass {
public: 
  Myclass() : a(1.0) {}

  float a;
  float &a_ref = a;

  void addOne() {
    a = a + 1.0;
  }
};

int main() {
  Myclass instance1;
  instance1.addOne();

  //prints 2:
  std::cout << "instance.a_ref is " << instance1.a_ref << std::endl;

  std::vector<Myclass> vec;
  Myclass instance2;
  vec.push_back(instance2);

  vec.at(0).addOne();

  //prints 1;
  std::cout << "vec.at(0).a_ref is " << vec.at(0).a_ref << std::endl;
  return 0;
}

I was compiling with g++ and -std=c++11, so I didn't notice the problem for a while. I see now the issue is probably to do with the synthesised copy constructor and the reference member. But what I'm not sure about is:

  1. Why is there different behaviour when the object is in a vector ?
  2. Why does g++ not give any warnings about this, using c++11 standard ?

Bonus question because I'm curious:

  1. What is initialized first, a or a_ref?
like image 677
badger5000 Avatar asked Jan 23 '15 11:01

badger5000


1 Answers

The problem is indeed with the defaulted copy constructor. The defaulted copy constructor initialises all members from the members of the source object. That is, the defaulted copy constructor is identical to this:

Myclass(const Myclass &src) :
  a(src.a),
  a_ref(src.a_ref)
{}

The defaulted copy constructor initialises all members, so it ignores any in-class initialisers.

This is also why pushing into a vector causes the problem. vec.at(0) was created as a copy of instance2, which means vec.at(0).a_ref refers to instance2.a. You could easily verify this by printing their addresses (live example).

like image 120
Angew is no longer proud of SO Avatar answered Sep 19 '22 18:09

Angew is no longer proud of SO