C++ 11引用类型的成员变量,矢量push_back后的不同行为

bad*_*000 16 c++ reference vector member c++11

当我把它推入一个向量时,我正在使用其他人的课程.它涉及一个成员变量,它是对另一个成员变量的引用.这是最小的自包含示例:

#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;
}
Run Code Online (Sandbox Code Playgroud)

我是用汇编g++-std=c++11,所以我没有注意到一会儿这个问题.我现在看到问题可能与合成的复制构造函数和引用成员有关.但我不确定的是:

  1. 当对象在向量中时,为什么会有不同的行为?
  2. 为什么不g++使用c ++ 11标准给出任何警告?

奖金问题,因为我很好奇:

  1. 什么是首先初始化,aa_ref

Rei*_*ica 16

问题确实存在于默认的拷贝构造函数中.默认的复制构造函数初始化源对象成员中的所有成员.也就是说,默认的拷贝构造函数与此相同:

Myclass(const Myclass &src) :
  a(src.a),
  a_ref(src.a_ref)
{}
Run Code Online (Sandbox Code Playgroud)

默认的复制构造函数初始化所有成员,因此它忽略任何类内的初始化程序.

这也是推入向量导致问题的原因.vec.at(0)是作为副本创建的instance2,意思vec.at(0).a_ref是指instance2.a.您可以通过打印地址(实例)轻松验证这一点.


eca*_*mur 7

隐式定义的复制/移动构造函数:

[...]执行其基地和成员的成员复制/移动.[ 注意: 忽略非静态数据成员的大括号或大小写.[...]

特别地,引用成员被直接初始化以引用源对象中对应的引用成员所引用的相同对象.

所以你的情况,vec.at(0).a_ref是指成员ainstance2.

编译器未检测到这一点,因为通常引用成员应引用类外的较长寿命对象.