当我把它推入矢量时,我正在使用其他人的类,这个类很奇怪。它涉及一个成员变量,它是对另一个成员变量的引用。这是最小的自包含示例:
#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;
}
我正在使用g++
和-std=c++11
进行编译,所以我暂时没有注意到这个问题。我现在看到问题可能与合成的复制构造函数和引用成员有关。但我不确定的是:
g++
没有使用c ++ 11标准给出任何警告?奖金问题,因为我很好奇:
a
或a_ref
? 答案 0 :(得分:16)
问题确实存在于默认的拷贝构造函数中。默认的复制构造函数初始化源对象成员中的所有成员。也就是说,默认的拷贝构造函数与此相同:
Myclass(const Myclass &src) :
a(src.a),
a_ref(src.a_ref)
{}
默认的拷贝构造函数初始化所有成员,因此忽略任何类内的初始化者。
这也是推入向量导致问题的原因。 vec.at(0)
被创建为instance2
的副本,这意味着vec.at(0).a_ref
指的是instance2.a
。您可以通过打印地址(live example)轻松验证这一点。
答案 1 :(得分:7)
隐式定义的复制/移动构造函数:
[...]执行其基础和成员的成员复制/移动。 [注意:忽略非静态数据成员的 brace-or-equal-initializers 。 [...]
特别是,引用成员是直接初始化的,以引用源对象中相应引用成员引用的同一对象。
因此,在您的情况下,vec.at(0).a_ref
是指a
的成员instance2
。
编译器未检测到这种情况,因为通常引用成员应引用类外的较长寿命对象。