【问题标题】:Inserting element to container: copy constructor messes up pointers将元素插入容器:复制构造函数弄乱了指针
【发布时间】:2016-12-25 23:31:14
【问题描述】:

我的问题是 默认的复制结构。弄乱了我的指针。

简化版:

  • 我有一个A 类,其默认 复制结构。

  • A 有 2 个成员对象:BC

  • B 有一个指向C 的指针。

情况:

  • 我将A 存储在std::vectorvector.emplace_back(A(...));

  • emplace_back 这样做:

    • 创建 A(设置B指向C的指针等)

    • 复制 A 到向量中。 (默认复制ctr:按复制)

    • 摧毁“起源”A.

结果:

  • 存储有一个A,它有一个B,它有一个指向 A 的C 的指针。它不再存在了。

简单的解决方案是:

  • A 中会有指向BC 的指针

但这不是很好,因为当 A 拥有 B 和 C 并且 B 和 C 与 A 共享生命周期时,为什么要拥有指针。

问题:

  • 难道没有比在 A 中使用指针更好的方法吗?

  • 或者没有比搞乱复制构造函数实现更简单的方法吗?

  • 我以为 emplace 是“就地”构造的,那为什么还需要一个拷贝 ctr 呢?

【问题讨论】:

  • 我不明白问题是什么。也许你会提供相关的示例代码来看看实际发生了什么......根据你的描述,C 似乎应该有一个构造函数来获取正确的B 对象的地址,A 应该有合适的复制构造函数/copy 分配以正确设置包含的 C 对象上的指针。
  • 我删除了我的答案,因为它是构造对象 in-place 的提示,但没有解决弄乱指针的主要问题。您需要发布一些示例代码或 MCVE 以获得完整的解决方案。
  • 一个 emplace 可以触发重新分配,从而复制或移动元素
  • 顺便说一句:这是使用 emplace 的错误方式——基本上你是在调用 push_back。您应该只将构建 A 所需的参数 oass 到 emplace_back,然后它可以就地构建 A,而不需要临时的。
  • 一些具有所需输出与实际输出的示例代码(即使抛出编译器错误)将有助于回答您的问题。很多用户只喜欢看代码,不喜欢看段落

标签: c++ c++11 containers copy-constructor


【解决方案1】:

难道没有比在 A 中使用指针更好的方法吗?

是的,有。此外,我看不出在A 中使用指针如何解决问题。

一种解决方案是为A 编写一个用户定义的复制构造函数,它将更新被复制成员的指针。

或者没有比弄乱复制构造函数实现更简单的方法吗?

不,复制构造函数是(也许可以说?)更新成员的成员指针的最简单方法。

我认为 emplace 构造“就地”

确实如此。

那么为什么它需要一个副本 ctr?

一般不会。

在这种情况下,它确实需要一个移动或复制构造函数,因为你传递了一个临时对象。向量中的对象是“就地”构造的,通过使用带有临时参数的移动(或复制,如果不可移动)构造函数。

相反,您可以将A 的构造函数的参数直接传递给emplace_back,这样就不会涉及临时。

请注意,就地构造对象不会阻止向量的元素被复制,除非您预先保留了内存以便不会发生重新分配。

【讨论】:

    【解决方案2】:

    您可以手动编写A 的复制构造函数来做正确的事情。

    如果一切都是标准布局,另一个计划是使用偏移指针。偏移指针存储指针本身与其指向的地址之间的差异。它通常使用 max(ptrdiff_t) 作为 null。

    如果仔细编写,这些允许指向子结构的指针默认是可复制的,因为两者的相对地址在复制后保持不变。

    但是,可能更好的计划是扩充B 中的所有方法以获取指向C 的指针,并在每次传递它而不是存储冗余状态。

    从上面确定正确答案的很多因素都与ABC的含义以及它们真正的独立程度有关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-21
      • 2016-04-13
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多