在一个临时std::initializer_list上迭代,范围基于for
Iterating over a temporary std::initializer_list with range based for
给定以下代码
#include <iostream>
#include <initializer_list>
#include <string>
int a, b;
int main() {
for (auto p : std::initializer_list<std::pair<int &, std::string>>{
{ a, "a" },
{ b, "b" },
})
{
std::cout << p.second << ": " << p.first << 'n';
}
}
我期望输出
a: 0
b: 0
和gcc和clang同意,然而,Visual Studio 2013 Update 5(我的版本,不确定rextester使用什么)不同意并打印如下:
: 0
: 0
Visual Studio有一个std::initializer_list
的问题,但它应该已经修复自更新2。
这是一个错误在Visual Studio或我调用未定义或未指定的行为?
在cppreference的"Explanation"一节中,range-for循环相当于:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end;
++__begin) {
range_declaration = *__begin;
loop_statement
}
}
可以看到,迭代范围(range_epxression
)被绑定到一个转发引用。在你的例子中,后者变成了一个右值引用,因为你的initializer_list
是一个临时的,它的生命周期因此被扩展到整个for
循环。
from cppreference.com:
底层数组不保证在初始化列表对象的生命周期结束后仍然存在。std::initializer_list的存储是未指定的(也就是说,根据具体情况,它可以是自动、临时或静态只读内存)。(直到c++ 14)
底层数组是一个临时数组,其中的每个元素都是从原始初始化列表的相应元素复制初始化的(除非窄化转换无效)。底层数组的生命周期与任何其他临时对象相同,只是从数组初始化initializer_list对象会扩展数组的生命周期,就像将引用绑定到临时对象一样(有相同的例外,例如初始化非静态类成员)。底层数组可以在只读内存中分配。(因为c++ 14)
从这里我可以推断出编译器出错了,因为initializer_list的生命周期应该在右括号之后结束。
相关文章:
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 循环挂起迭代的 std::擦除 on std::list
- std::list 中的迭代器感知对象
- 当通知迭代器参数初始化为空列表的开头时,list::insert 行为是什么?
- 如何使用 std::list 模板的迭代器擦除
- 如果我在下面的代码中使用 list 而不是 vector,为什么在我尝试在迭代器之间执行减法的行中编译失败?
- 使用迭代器对 std::list 进行排序
- 如何从该列表的元素中获取 std::list<T>::迭代器?
- 为什么 std::list 迭代器没有运算符+
- std::list.end() 不返回"past-the-end"迭代器
- 我可以在 std::list 中移动元素而不会使迭代器或引用无效,但是如何移动呢?
- std::list 中的 rbegin() 永远不会等于指向列表的迭代器?
- 如何在迭代boost :: Intrusive :: list时擦除
- 在迭代器时从 std::list 中删除条目
- C++ "argument list for class template "迭代器" is missing"错误
- 无法将 std::set 中的元素迭代器插入到 std::list
- 获取迭代器在基类型 "intrusive doubly linked list" 的指针字典中的位置
- c++中简单迭代list over map的性能比较