为什么我不能将别名带到std :: vector元素?

时间:2017-03-05 02:02:04

标签: c++ c++11 vector

Rust for C++ programmers的幻灯片6上,有以下代码:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<string> v;
    v.push_back("Hello");

    string& x = v[0];
    v.push_back("world");

    cout << x << endl;
    return 0;
}

运行它我得到了:

g++ --std=c++11 main.cpp -I . -o main
./main
P▒▒o▒Y ▒▒2.▒8/.▒H/.▒H/.▒X/.▒X/.▒h/.▒h/.▒x/.▒x/.▒▒/.
@▒▒
...

它继续为更多的东西。我发现了一些关于别名和向量的问题:

  1. int vs const int&
  2. Changing things from a vector
  3. 但是我无法弄清楚为什么别名根据它们不起作用。我查看了http://en.cppreference.com/w/cpp/container/vector,关于向量定义,但它似乎只是继续在磁盘上分配内存。我理解字符串Helloworld分配在程序的数据成员的某处,就像g++ main.cpp -S上的汇编一样:

    ...
    .lcomm _ZStL8__ioinit,1,1
        .def    __main; .scl    2;  .type   32; .endef
        .section .rdata,"dr"
    .LC0:
        .ascii "Hello\0"
    .LC1:
        .ascii "world\0"
        .text
        .globl  main
        .def    main;   .scl    2;  .type   32; .endef
        .seh_proc   main
    main:
    ...
    

    如果我不推送第二个元素world,则程序正确运行。因此,为什么别名在第二次推送后失去了对第一个向量元素的引用?

3 个答案:

答案 0 :(得分:4)

当调用方法push_back时,向量可以重新分配已使用的内存,结果引用变为无效。

在向向量添加新元素之前,您可以保留足够的内存。在这种情况下,引用将是有效的。例如

vector<string> v;
v.reserve( 2 );

v.push_back("Hello");

string& x = v[0];
v.push_back("world");

这是一个示范程序

#include <iostream>
#include <vector>
#include <string>

int main() 
{
    std::vector<std::string> v;
    v.reserve( 2 );

    v.push_back("Hello");

    std::string& x = v[0];
    v.push_back("world");

    std::cout << x << ' ' << v[1];
    std::cout << std::endl;

    return 0;
}

它的输出是

Hello world 

答案 1 :(得分:3)

当您执行第二次push_back时,应假定迭代器和引用无效。向量可能可能会调整其数据块的大小 - 很可能是在另一个内存位置。

因此,变量引用x引用未分配的内存,随后会导致未定义的行为。

答案 2 :(得分:2)

push_back()调整向量的大小(向其添加元素时的内在因素)。

这会使引用该向量元素的所有迭代器,指针和引用无效。

通过无效的迭代器,指针或引用(即在调整大小操作之前有效但不在之后)访问向量的元素会给出未定义的行为。

x在初始化之后和输出语句之前调用push_back()无效