1

下面程序的输出是

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: %d\n", s, strlen(s));
        break;
    }
    printf("2: %s strlen: %d\n", s, strlen(s));

    for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
    {
        s = (*it).first.c_str();
        printf("3: %s strlen: %d\n", s, strlen(s));
        break;
    }
    printf("4: %s strlen: %d\n", 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: %d\n", s, strlen(s));
        break;
    }
    printf("6: %s strlen: %d\n", s, strlen(s));

    return 0;
}

更新对于几乎没有 C++ 背景的程序员的解释将不胜感激。

4

3 回答 3

5

在您的第一个示例中,您调用whichc_str()在-loopkvPair的范围内声明。退出循环for时结果无效,因为被破坏了。forkvPair

在第二个示例中,您调用c_str()映射中的值。结果只有在地图被销毁时才变得无效,这在_tmain(...)返回时发生。

在您的第三个示例中,您调用c_str()了一个临时对象(由要配对的演员创建​​),并且该临时对象在printf("5...调用之前被销毁。

解释

指向它所c_str()拥有的一些内存的指针string被调用,所以当它string被销毁时,访问指针是未定义的行为。

于 2012-07-12T06:28:19.937 回答
3

部分是偶然的。

在 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

于 2012-07-12T07:37:35.283 回答
0

第一个循环s指向该对中的数据-循环后该对超出范围,因此您的数据是伪造的

第二个和第三个循环s指向实际集合中的数据 - 所以它保持在范围内

于 2012-07-12T06:28:50.950 回答