无效实例对放置实例的引用是什么? [英] What is the reference to an emplaced instance invalidated?

查看:65
本文介绍了无效实例对放置实例的引用是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个存储一些数据的类,还有一个需要修改某些父类数据的成员。请考虑以下简化示例:

I have a class that stores some data and also a member that needs to modify some of the parent class data. Consider the following simplified example:

#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 。我假设由于嵌入而发生了一些未定义的行为,但是我无法查明根本原因是什么。

When I run this, one of the emplaced instances correctly reports size 2, but the other one reports size 0. I assume there's some undefined behaviour happening due to emplacing, but I cannot pinpoint what is the root cause.

此外,是否有一种更优雅的方式来表示这种情况?

Also, is there a more elegant way to represent this scenario?

实时示例: http:// coliru.stacked-crooked.com/a/e68ae9bf2b7e6b75

推荐答案

执行第二次 emplace_back ,向量可能会进行重新分配操作:为了增长,它会分配一个新的内存块并将对象从旧的移动到新的对象,并释放旧的内存块。

When you do the second emplace_back, the vector may undergo a reallocation operation: in order to grow, it allocates a new memory block and moves the objects from the old to the new, and frees the old memory block.

您的修饰符对象在移动时会生成一个悬空引用:目标对象的引用与旧引用所引用的对象相同。

Your Modifier object generates a dangling reference when moved: the target object's reference refers to the same object that the old reference did.

要解决此问题,您可以在 Container 中添加一个移动构造函数,然后添加或删除复制构造函数。 修饰符必须初始化为引用它所属的 Container ;但是默认的复制构造函数和移动构造函数将初始化修饰符来引用要从中复制/移动的源。

To fix this you could add a move-constructor to Container, and either add or delete the copy-constructor. The Modifier has to be initialized to refer to the Container it is a member of; but the default copy- and move-constructors will initialize the Modifier to refer to the source being copy/move'd from.

例如:

Container(Container&& o) : stuff(std::move(o.stuff)), modifier(stuff) {}
Container(Container const& o) : stuff(o.stuff), modifier(stuff) {}

这篇关于无效实例对放置实例的引用是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆