C++迭代器难题
C++ iterator conundrum
以下程序的输出为
1: foo strlen: 3
2: strlen: 0
3: foo strlen: 3
4: foo strlen: 3
5: strlen: 0
6: strlen: 0
我不明白
- 为什么
1
打印字符串,但2
没有和 - 三个循环之间的区别是什么
资料来源:
#include "stdafx.h"
#include <map>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
map<string, string> m;
m["foo"] = "bar";
const char * s;
for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
{
pair<string, string> kvPair = *it;
s = kvPair.first.c_str();
printf("1: %s strlen: %dn", s, strlen(s));
break;
}
printf("2: %s strlen: %dn", s, strlen(s));
for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
{
s = (*it).first.c_str();
printf("3: %s strlen: %dn", s, strlen(s));
break;
}
printf("4: %s strlen: %dn", s, strlen(s));
for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
{
s = ((pair<string, string>) (*it)).first.c_str();
printf("5: %s strlen: %dn", s, strlen(s));
break;
}
printf("6: %s strlen: %dn", s, strlen(s));
return 0;
}
更新 对于背景很少C++程序员的解释将不胜感激。
在第一个示例中,您在for
循环范围内声明的kvPair
上调用c_str()
。退出for
循环时,结果将变为无效,因为kvPair
被销毁。
在第二个示例中,对映射中的值调用c_str()
。仅当地图被销毁时,结果才会失效,这在_tmain(...)
返回时发生。
在第三个示例中,您在临时(由强制转换为配对(上调用c_str()
,并且在调用printf("5...
之前销毁该临时。
解释
c_str()
返回的指针指向调用它string
拥有的某个内存,因此当该string
被销毁时,访问指针是未定义的行为。
部分是偶然的。
在 1/2 中,您在循环中创建一个局部变量,复制值从地图出来变成kvPair
. 您将s
设置为指向此中的数据复制。 当您退出块。 通过任何方式:break
、goto
、例外或只是完成环形体并再次穿过它——每次通过循环,你会得到一个新的kvPair
,它在循环结束时被破坏身体。 s
指向kvPair.first
内部的数据,以及任何s
的使用(即使只是简单地复制它(在kvPair
被销毁后是未定义的行为。 任何事情都可能发生,发生的事情很可能是根据调试检查和优化的级别而有所不同,或者甚至取决于程序的完全不相关的方面。 (如果你始终得到一个空字符串,可能有一些设计不佳调试检查正在进行中。 设计良好的调试检查将导致立即崩溃,因此您会看到错误。
在 2/3 中,您使用地图的实际内容初始化s
,因此它是在地图被破坏或元素从地图。
在 4/5 中,您创建一个临时:T( initialization )
构造一个对于任何类型T
,使用给定的初始化,类型T
的临时,包括类型 std::pair<std::string, std::string>
. (这不完全是真;例如,如果T
是引用,则行为是不同的。然后初始化s
以指向此临时数据。 这临时的生存期只是到完整表达式的末尾包含它,因此s
的内容在分号处变为无效结束语句(在本例中是完整表达式(。 与 1/2 一样,当您使用 s
在此之后。
第一个循环s
指向该对中的数据 - 该对在循环后超出范围,因此您的数据是伪造的
第二个和第三个循环s
指向实际集合中的数据 - 因此它保持在范围内
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 如何在c++迭代器类型中包装std::chrono
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 对于set上的循环-获取next元素迭代器
- 为什么output_editor Concept不需要output_e迭代器标记
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 使用迭代器时如何访问对象在向量中的位置?
- std::vector::迭代器是否可以合法地作为指针
- 跟随整数索引列表的自定义类迭代器
- 不明白迭代器,引用和指针失效,一个例子
- 我可以使用反向迭代器作为ForwardIt吗
- ESP8266单片机矢量迭代器的C++问题
- 如何在C++中将迭代器作为函数参数传递
- 是否应避免从非常量迭代器转换为常量迭代器?
- 如何在 c++ 中将字符串迭代器变量传递给函数?
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- C++迭代器难题