在空std :: vector上使用operator []

Aku*_*ete 8 c++ vector visual-studio-2010

我刚才被告知,在c ++中使用std :: vector作为异常安全动态数组而不是分配原始数组是常见的...例如

{
    std::vector<char> scoped_array (size);
    char* pointer = &scoped_array[0];

    //do work

} // exception safe deallocation
Run Code Online (Sandbox Code Playgroud)

我已多次使用此约定没有问题,但是我最近将一些代码移植到Win32 VisualStudio2010(之前只在MacOS/Linux上)并且我的单元测试正在破坏(stdlib抛出一个断言)当矢量大小恰好是零.

我知道写一个这样的数组会有问题,但是这个假设打破了这个解决方案作为原始指针的替代.考虑以下函数,n = 0

void foo (int n) {
   char* raw_array = new char[n];
   char* pointer = raw_array;
   file.read ( pointer , n );
   for (int i = 0; i < n; ++i) {
      //do something
   }
   delete[] raw_array;
}
Run Code Online (Sandbox Code Playgroud)

虽然可以说是多余的,但上面的代码完全合法(我相信),而下面的代码将在VisualStudio2010上抛出一个断言

void foo (int n) {
   std::vector<char> scoped_array (n);
   char* pointer = &scoped_array[0];
   file.read ( pointer , n );
   for (int i = 0; i < n; ++i) {
  //do something
   }
}
Run Code Online (Sandbox Code Playgroud)

我一直在使用未定义的行为吗?我的印象是operator []没有错误检查,这是std :: vector <>的有效使用.还有其他人遇到过这个问题吗?

--edit: 感谢所有有用的回复,回复人们说它是未定义的行为.有没有办法替换上面的原始数组分配n = 0

虽然说检查n = 0作为例外情况将解决问题(它会).有许多模式不需要特殊情况(例如上面的原始指针示例),所以可能需要使用std :: vector <>以外的东西吗?

MSa*_*ers 8

LWG问题464.这是一个已知的问题.C++ 0x(部分由MSVC 2010实现)通过添加.data()成员来解决它.


Ste*_*sop 5

就 C++ 标准而言,operator[]不保证不检查,只是(与at())不保证检查。

您会期望在非检查实现中,&scoped_array[scoped_array.size()]会在向量分配的数组内或在其末尾生成一个合法指针。这不是明确保证的,但对于给定的实现,您可以通过查看其来源进行验证。对于空向量,可能根本没有分配(作为优化),并且我vector在标准的部分中看不到任何内容,该部分定义了scoped_array[0]表 68 以外的结果。

从表 68 开始,您可能会说您的表达式的结果是&*(a.begin() + 0),它非法取消引用了一个末端迭代器。如果您的实现的向量迭代器只是一个指针,那么您可能会逃脱 - 如果不是,您可能不会,显然您的不是。

我忘记了参数的结果,&*即不能取消引用的指针上的是否为无操作。IIRC 从标准中不清楚(某处有些含糊不清),这引发了修复标准以使其明确合法的请求。这表明它实际上适用于所有或大多数已知的实现。

就我个人而言,我不会依赖于此,也不会禁用检查。我会重写你的代码:

char* pointer = (scoped_array.size() > 0) ? &scoped_array[0] : 0;
Run Code Online (Sandbox Code Playgroud)

或者在这种情况下只是:

char* pointer = (n > 0) ? &scoped_array[0] : 0;
Run Code Online (Sandbox Code Playgroud)

在我看来,在不知道大小至少为 n+1 的情况下使用向量的索引 n 是错误的,无论它是否在您禁用检查后在您的实现中实际工作。