为什么这个向量构造函数抛出 std::bad_alloc 异常?

Why this vector constructor throw std::bad_alloc exception?

#include <iostream>
#include <vector>

using namespace std;

void test_bad_alloc(unsigned char *start) {
    try {
        vector<int> v = vector<int>(start + 1, start - 13);
    }catch (bad_alloc) {
        std::cout<<"bad alloc"<<std::endl;
    }
}

int main() {
    unsigned char a[20] = {0};
    test_bad_alloc(a);
    return 0;
}

这段代码和我的真实项目差不多,我发现它会导致bad_alloc异常,为什么?这个vector的构造函数是不是有歧义?

vector<int>(ptr1, ptr2)调用的构造函数是带两个迭代器的范围构造函数。它尝试为从 ptr1 开始到 ptr2 之前结束的元素分配内存。但是由于您的 ptr2 小于 ptr1 ,您将分配负数的元素。

因为 ptr2=start-13 会在分配的数组之外引用,我猜你想要 ptr2=start+13.

您的程序在尝试计算 start - 13.

时出现未定义行为

start 指向 a 数组的第一个元素,因此 start - 13 创建了一个无效指针,因为它超出了数组的范围。你根本不能那样做,这也没有意义。您希望指针准确指向什么?

请注意 this is undefined behaviour 即使您不取消引用指针。

无论如何,未定义的行为意味着您的程序可以做任何事情,并且 "anything" 包括抛出随机异常。

事实上,我无法重现 std::bad_alloc 异常。例如,最新的 Clang 会抛出 std::length_error,而最新的 Visual C++ 只会崩溃。它还取决于编译器标志。

在您的情况下可能发生的情况是,编译器生成了二进制代码,该代码简单地继续使用无效指针并将其传递给向量构造函数,然后向量构造函数尝试从中创建一个巨大的整数范围,但失败了。

也许您本来打算这样做的?

void test_bad_alloc(unsigned char *start, unsigned char* end) {
    try {
        vector<int> v = vector<int>(start + 1, end - 13);
    }catch (bad_alloc) {
        std::cout<<"bad alloc"<<std::endl;
    }
}

// ...

test_bad_alloc(a, a + 20);

我也忍不住注意到矢量定义行中的 Java-ism。你可以,也应该这样写:

vector<int> v(start + 1, end - 13);

问题在vector<int> v = vector<int>(start + 1, start - 13);

范围构造函数期望

vector (InputIterator first, InputIterator last,
          const allocator_type& alloc = allocator_type());

即第一个元素到最后一个元素。但是,您使用的 start - 13 代替了 SecondIterator,它位于已分配数组的内存 space 之外。

在最好的情况下,它也可能在您的进程的内存之外 space,并可能导致分段错误,在最坏的情况下,它可能会获得垃圾值,用错误数据覆盖文件或通过套接字发送错误消息。