使用{{}}初始化std::vector是否引发未定义行为?为何与v{}表现不同?
关于std::vector初始化与越界访问的问题解答
先贴出你提供的测试代码:
#include <iostream> #include <vector> int main() { std::vector<int> v{{}}; v[10] = 11; // if initialize with v{}, segmentation fault. std::cout << "v[10]:" << v[10] << std::endl; // prints v[10]:11 for (auto e : v) // prints only v[x]:0 std::cout << "v[x]:" << e << std::endl; } // result: // v[10]:11 // v[x]:0
问题1:通过v[10]访问元素是否会导致未定义行为?
是的,这绝对属于未定义行为。
C++标准明确规定,std::vector的operator[]仅允许访问索引在[0, v.size())范围内的元素。你的代码里,不管是v{{}}还是v{}初始化的vector,v.size()分别是1和0,10都远远超出了合法索引范围。
你看到的"正常运行"只是巧合——v{{}}初始化的vector底层预分配的内存空间(即capacity())刚好足够覆盖索引10的位置,所以写操作没触发内存错误。但这种行为完全不被标准保证,换编译器、换运行环境甚至换个编译选项,都可能直接崩溃或出现更诡异的问题,绝对不能依赖。
问题2:为何使用v{{}}初始化的代码可正常运行,而使用v{}初始化的代码会触发段错误?
核心是两种初始化方式得到的vector状态完全不同:
v{}:调用vector的默认构造函数,创建一个空vector,此时v.size() = 0,多数编译器实现下v.capacity()也为0。这时候访问v[10],本质是访问一块根本没分配给vector的内存,触发段错误是必然的。v{{}}:这是列表初始化,外层大括号触发vector的列表构造函数,内层{}会值初始化一个int(结果为0),最终得到的vectorv.size() = 1。而很多编译器(比如GCC、Clang)的vector实现会默认预分配16个元素的空间(即capacity() = 16),这时候虽然v.size()只有1,但预分配的内存能覆盖到索引10的位置,所以写操作没触发段错误。但这依然是未定义行为,只是刚好没撞上内存保护机制而已。
内容的提问来源于stack exchange,提问作者starriet 차주녕
相关产品推荐
相关产品推荐

