我有一个存储一些数据的类,还有一个需要修改某些父类数据的成员。考虑下面的简化示例:
#include <iostream>
#include <vector>
#include <string>
struct Modifier {
std::vector<std::string> &stuff;
Modifier(std::vector<std::string> &ref) : stuff(ref) {}
void DoIt() {
std::cout << "stuff.size = " << stuff.size() << '\n';
}
};
struct Container {
std::vector<std::string> stuff;
Modifier modifier;
std::vector<std::string> BuildStuff(int n) {
return std::vector<std::string>{"foo", std::to_string(n)};
}
Container(int n) : stuff(BuildStuff(n)), modifier(stuff) {}
};
int main()
{
std::vector<Container> containers;
containers.emplace_back(5);
containers.emplace_back(42);
containers[0].modifier.DoIt();
containers[1].modifier.DoIt();
return 0;
}
运行此命令时,一个放置的实例正确报告大小2
,而另一个实例报告大小0
。我假设由于嵌入而发生了一些未定义的行为,但我无法查明根本原因是什么。
还有,还有一种更优雅的方式来表示这种情况吗?
答案 0 :(得分:3)
当您执行第二个emplace_back
时,矢量可能会进行重新分配操作:为了增长,它会分配一个新的存储块并将对象从旧的移动到新的存储块,并释放旧的存储块
您的Modifier
对象在移动时会生成一个悬空引用:目标对象的引用与旧引用所引用的对象相同。
要解决此问题,您可以将移动构造函数添加到Container
,然后添加或删除复制构造函数。 Modifier
必须初始化为引用它所属的Container
;但是默认的复制构造函数和移动构造函数将初始化Modifier
来引用要从其复制/移动的源。
例如:
Container(Container&& o) : stuff(std::move(o.stuff)), modifier(stuff) {}
Container(Container const& o) : stuff(o.stuff), modifier(stuff) {}