【发布时间】:2023-04-05 16:11:01
【问题描述】:
在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/.▒▒/.
@▒▒
...
而且它会继续提供更多的东西。我发现了一些关于别名和向量的问题:
但我无法根据它们弄清楚为什么别名不起作用。我查看了关于向量定义的http://en.cppreference.com/w/cpp/container/vector,但它似乎只是在磁盘上分配了继续内存。我知道字符串Hello 和world 分配在程序数据成员的某个位置,就像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,程序会正确运行。因此,为什么别名在第二次推送后丢失了对第一个向量元素的引用?
【问题讨论】:
-
查看
push_back的页面:en.cppreference.com/w/cpp/container/vector/push_back -
等等,你正在阅读的幻灯片解释了它。
-
对不起,这是
push_back文档中的第一句话。If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.真正的问题是他们为什么要这样做。 -
如果不这样做,你将如何实现一个为所有元素都拥有一块连续内存的数据结构?你可以想象一些技巧,但到那时,你首先会失去从向量中获得的收益。
-
是的,这就是问题所在。通常你不能这样做,因为这是分配内存的方式。例如,如果我在向量的末尾添加一个新元素并且我需要增加它的大小,我需要幸运的是,在向量的末尾有空闲内存。我敢打赌,情况绝不会如此,因此需要在一个足以容纳整个结构的洞内的其他地方分配一个完整/全新的内存块。此外,根据动态数组的当前大小,分配更多空间的操作成本非常高 O(n)。