【问题标题】:std::vector::reserve allows random access before push_backstd::vector::reserve 允许在 push_back 之前进行随机访问
【发布时间】:2020-08-23 10:29:55
【问题描述】:

我最近在网上了解到std::vector::reserve。网站说在std::vector 中保留内存不会改变向量的大小,而是增加std::vector 的容量。保留后,尝试访问随机元素应该会崩溃。

但是,当我运行这段代码时:

#include <iostream>
#include <vector>

using namespace std;

int main(){
    vector <int> v;
    v.reserve(1000000);
    
    v[4] = 5;
    cout << v[4] << endl; // this line and the above line should cause errors

    return 0;
}

什么都没有发生。程序运行并将5 打印到屏幕上,我根本没有收到任何错误。

我不确定我是否在这里犯了错误,那么有人可以告诉我为什么上面的程序会运行吗?

【问题讨论】:

  • 未定义的行为意味着任何事情都可能发生;它不保证会崩溃。
  • v[4] = 5; 这会导致越界访问,之后的所有内容都是 UB。试试v.at(4) = 5;,你会得到你期望的错误。
  • 它会如何崩溃?内存已分配,内存不知道整个大小与容量的关系
  • 您会看到终端学大量与 STL 函数和较低级别的 c api 调用一起使用,这就是为什么仔细阅读这些语言中的文档非常重要的原因
  • @harold,标准库实现可以告诉编译器假设索引小于大小。在这种假设下,编译器会优化此代码及其周围的代码,从而导致崩溃。例如,std::string str(input); if (something) { v.reserve(1000000); v[4] = 5; str += "foo"; } cout &lt;&lt; str[10];。当编译器知道 v[4] 导致 UB 时,它可以意识到 if 语句永远不会发生,str 将保留其初始值(可能小于 11 个元素)。然后可能会发生常规的越界索引,这是常见的崩溃原因。

标签: c++ vector


【解决方案1】:

保留后,尝试访问随机元素会崩溃。

不,更正确的说法是“保留后,尝试访问随机元素将导致未定义的行为”(a)

未定义的行为意味着完全未定义。它可能有效,也可能无效。它可能似乎可以工作,但会为以后在您的程序中发生的严重失败设置条件。它可能无法在另一个实现中工作,甚至可能在一周中的某些日子在相同的实现中无法工作。

底线,不要这样做。


(a) ISO C++20 中的表 69 有两个元素访问操作,说明完全相同的内容:

a[n] - 返回引用,或 const 引用常量 a。语义:*(a.begin() + n)a.at(n) - 返回引用,或 const 引用常量 a。语义:*(a.begin() + n).

但紧随其后的注释澄清了差异:

成员函数at() 提供对容器元素的边界检查访问。 at() 抛出 out_of_range 如果n &gt;= a.size()

因此,如果您需要它“崩溃”(引用是因为它确实引发了异常而不是崩溃),请使用后者。

【讨论】:

    猜你喜欢
    • 2020-09-22
    • 2023-03-21
    • 1970-01-01
    • 2016-06-15
    • 2013-06-18
    • 1970-01-01
    • 2021-05-22
    相关资源
    最近更新 更多