The output of the program below is
1: foo strlen: 3
2: strlen: 0
3: foo strlen: 3
4: foo strlen: 3
5: strlen: 0
6: strlen: 0
I don’t understand
- why
1prints the string, but2does not and - what the difference between the three loops is
The source:
#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;
}
Update An explanation for programmers with little C++ background would be appreciated.
Partially by chance.
In 1/2 you create a local variable within the loop, copying the value
out of the map into
kvPair. You setsto point to data in thiscopy. The copy is destroyed (destructor called) when you exit the
block. By any means:
break,goto, an exception, or simply finishingthe loop body and going through it again—each time through the
loop, you get a new
kvPair, which is destructed at the end of the loopbody.
spoints to data insidekvPair.first, and any use ofs(even simply copying it) after
kvPairhas been destructed is undefinedbehavior. Anything can happen, and what happens is likely to be
different depending on the level of debug checking and optimization, or
even depending on totally unrelated aspects of the program. (If you
consistently get an empty string, there is probably some poorly designed
debug checking going on. Well designed debug checking would cause an
immediate crash, so you would see the error.)
In 2/3, you initialize
swith the actual contents of the map, so it isvalid until the map is destructed, or the element is removed from the
map.
In 4/5, you create a temporary:
T( initialization )constructs atemporary of type
T, using the initialization given, for any typeT,including type
std::pair<std::string, std::string>. (This isn’t quitetrue; if
Tis a reference, for example, the behavior is different.)And you initialize
sto point to data within this temporary. Thelifetime of a temporary is only to the end of the full expression which
contains it, so the contents of
sbecome invalid at the semicolonending the statement (which in this case is the end of the full
expression). As in 1/2, undefined behavior ensues when you use
safter this.