我正在使用别人的类,当我把它推入一个向量时,它表现得很奇怪。它涉及一个成员变量,该变量是对另一个成员变量的引用。下面是一个最小的自包含示例:
#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
,
发布于 2015-01-23 19:52:29
问题确实出在默认的复制构造函数上。默认的复制构造函数初始化源对象成员中的所有成员。也就是说,默认的复制构造函数与以下内容相同:
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)轻松地验证这一点。
发布于 2015-01-23 19:52:56
隐式定义的复制/移动构造函数:
...执行对其基表和成员执行成员级复制/移动。[注意:忽略非静态数据成员的大括号或等于初始值设定项。..。
具体地说,引用成员被直接初始化以引用源对象中的相应引用成员所引用的同一对象。
因此,在您的示例中,vec.at(0).a_ref
指的是instance2
的成员a
。
编译器不会检测到这一点,因为通常情况下,引用成员应该引用类外部的较长生存期的对象。
https://stackoverflow.com/questions/28109083
复制相似问题