I’ve created a simple test case exhibiting a strange behavior I’ve noticed in a larger code base I’m working on. This test case is below. I’m relying on the STL Map’s “[ ]” operator to create a pointer to a struct in a map of such structs. In the test case below, the line…
TestStruct *thisTestStruct = &testStructMap["test"];
…gets me the pointer (and creates a new entry in the map). The weird thing I’ve noticed is that this line not only causes a new entry in the map to be created (because of the “[ ]” operator), but for some reason it causes the struct’s destructor to be called two extra times. I’m obviously missing something – any help is much appreciated!
Thanks!
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
the code above outputs the following…
/*
Marker One
TestStruct Constructor! //makes sense
TestStruct Destructor! //<---why?
TestStruct Destructor! //<---god why?
Marker Two
TestStruct Destructor! //makes sense
*/
…but I don’t understand what causes the first two invocations of TestStruct’s destructor?
(I think the last destructor invocation makes sense because testStructMap is going out of scope.)
The functionality of
std::map<>::operator[]is equivalent toexpression, as specified in the language specification. This, as you can see, involves default-constructing a temporary object of type
T, copying it into astd::pairobject, which is later copied (again) into the new element of the map (assuming it wasn’t there already). Obviously, this will produce a few intermediateTobjects. Destruction of these intermediate objects is what you observe in your experiment. You miss their construction, since you don’t generate any feedback from copy-constructor of your class.The exact number of intermediate objects might depend on compiler optimization capabilities, so the results may vary.