为何std::vector::insert传入空初始化列表时无实际操作效果
问题现象
#include <iostream> #include <vector> int main() { std::cout<<"Hello World"; std::vector<std::vector<int>> v; while(v.size() <= 2){ v.insert(v.begin(),{}); //1 std::cout << "!"; } return 0; }
上述代码运行时会陷入无限循环,持续输出感叹号:循环内每次调用insert后,v.size()始终没有增长,容器长度一直为0,永远达不到退出循环的条件。
对照测试
对代码做两种修改后,循环都能在执行3次插入后正常终止:
- 第一种:给初始化列表加入元素
// ... v.insert(v.begin(),{0}); //1 // ...
- 第二种:显式传入临时
std::vector<int>对象
// ... v.insert(v.begin(),std::vector<int>()); //1 // ...
根本原因
该现象由C++重载决议规则和std::vector::insert的重载设计共同导致,全程不存在隐式转换失败,因此不会触发编译错误:
- 首先明确前提:
v的元素类型T是std::vector<int>,insert接口存在两个和当前调用参数数量匹配的重载:- 重载A:
iterator insert(const_iterator pos, const T& value),作用是在指定位置插入1个T类型的元素 - 重载B:
iterator insert(const_iterator pos, std::initializer_list<T> ilist),作用是在指定位置插入初始化列表中包含的所有T类型元素
- 重载A:
- C++重载决议有明确规则:当函数实参是花括号初始化列表时,如果候选重载中存在参数类型为对应元素类型的
std::initializer_list,该重载会被优先匹配。 - 原始代码传入空花括号
{}时,编译器优先匹配重载B:传入的是一个空的std::initializer_list<std::vector<int>>,插入空列表不会新增任何元素,因此v.size()永远不变,触发无限循环。 - 两种修改方式能正常运行的逻辑:
- 传入
{0}时,依然优先匹配重载B,此时初始化列表包含1个元素0,会构造出1个std::vector<int>元素插入容器,每次调用size加1,循环正常终止 - 传入
std::vector<int>()时,实参类型明确为std::vector<int>,和重载A的参数类型完全匹配,因此调用重载A插入1个空vector,每次调用size加1,循环正常终止
- 传入
内容的提问来源于stack exchange,提问作者Dávid Tóth
相关产品推荐
相关产品推荐

