C++迭代器难题

C++ iterator conundrum

本文关键字:难题 迭代器 C++      更新时间:2023-10-16

以下程序的输出为

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设置为指向此中的数据复制。 当您退出块。 通过任何方式:breakgoto、例外或只是完成环形体并再次穿过它——每次通过循环,你会得到一个新的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指向实际集合中的数据 - 因此它保持在范围内