【问题标题】:Address of an instance emplaced to std::vector is invalid放置到 std::vector 的实例的地址无效
【发布时间】:2015-06-14 15:20:03
【问题描述】:

我有 2 个std::vectors:

  • 到第一个向量,我放置实例
  • 到第二个向量,我想存储刚刚放置的实例的地址

但它不起作用,即存储的地址与放置实例的地址不同。

如果这很重要,我在 Linux 上使用 g++ 5.1 和 clang 3.6 和 -std=c++11。

这是一个说明问题的工作示例。

#include <iostream>
#include <vector>

struct Foo {
  Foo(int a1, int a2) : f1(a1), f2(a2) {}

  int f1;
  int f2;
};

int main(int, char**) {
  std::vector<Foo> vec1;
  std::vector<Foo*> vec2;

  int num = 10;
  for (int i = 0; i < num; ++i) {
    vec1.emplace_back(i, i * i);

    // I want to store the address of *emplaced* instance...
    vec2.push_back(&vec1.back());
  }

  // same
  std::cout << "size 1: " << vec1.size() << std::endl;
  std::cout << "size 2: " << vec2.size() << std::endl;
  // same for me
  std::cout << "back 1: " << &vec1.back() << std::endl;
  std::cout << "back 2: " << vec2.back() << std::endl;
  // typically differ ?
  std::cout << "front 1: " << &vec1.front() << std::endl;
  std::cout << "front 2: " << vec2.front() << std::endl;

  for (int i = 0; i < num; ++i) {
    std::cout << i + 1 << "th" << std::endl;
    // same for last several (size % 4) for me
    std::cout << "1: " << &vec1[i] << std::endl;
    std::cout << "2: " << vec2[i] << std::endl;
  }
}

问题

  • 这是正确的行为吗?我猜这是由存储临时实例的地址引起的,但我想知道标准是否允许(只是好奇)。
  • 如果上述情况属实,如何解决这个问题?我通过将第一个更改为 vector&lt;unique_ptr&lt;Foo&gt;&gt; 解决了这个问题,但有什么惯用的方法吗?

【问题讨论】:

  • 你不能真正将指向实例的指针存储在向量中,因为向量是动态的并且可以随时重新分配,这意味着你存储的指针将变得无效。
  • @JoachimPileborg 这闻起来像是一个答案!

标签: c++11 vector standards emplace


【解决方案1】:

两种选择:

1) 您可以简单地修复您的测试。您只需要先测试预分配足够的内存

 vec1.reserve(10);

嗯,这是std::vector 的实现细节。随着越来越多的项目被添加到std::vector,它需要为它们获得更多空间。这个空间必须是连续的。因此,当没有足够的空间容纳新元素时,std::vector 会分配更大的内存块,将现有元素复制到其中,添加新元素,最后释放它之前使用的内存块。因此,您存储在 vec2 中的地址可能会变得无效。

但是,如果您为 10 个元素预先分配了足够的内存,那么您的代码是正确的。

或者,因为保留内存是一件很棘手的事情

2) 使用std::deque,因为在双端队列的任一端插入和删除永远不会使指针或对其余元素的引用 (http://en.cppreference.com/w/cpp/container/deque) 无效,并且忘记地址无效的问题。所以不需要预留内存。

【讨论】:

  • 等等,@JoachimPileborg 说重新分配可以“随时”发生,但只有在超出预分配内存时才会发生?
  • @nsuke 是的,这使得像保留内存这样的解决方案变得危险,因为您只能预先分配一定数量的内存,但如果超过了,仍然会重新分配。此外,当从向量中删除元素时,指针(和迭代器)也会变得无效。
  • 感谢大家的澄清。所以只要我避免超出容量,就保证有效。
  • 非常适合我的用例。感觉比“小心”的预分配更安全,也比 vector>.
猜你喜欢
  • 2014-12-12
  • 2017-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多