安装到std :: vector的实例的地址无效

时间:2015-06-14 15:20:04

标签: c++11 vector standards emplace

我有2 std::vector s:

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

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

如果它很重要,我在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<unique_ptr<Foo>>来解决此问题,但是有任何惯用的方法吗?

1 个答案:

答案 0 :(得分:1)

两个选项:

1)您可以简单地修复您的测试。您只需要在测试中首先使用

预先分配足够的内存
 vec1.reserve(10);

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

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

或者,因为保留记忆是一件棘手的事情

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