In an STL Map of structs, why does the "[ ]" operator cause the struct's dtor to be invoked 2 extra times?

c++, constructor, copy-constructor, stl, temporary-objects

Solution

The functionality of `std::map<>::operator[]` is equivalent to

(*((std::map<>::insert(std::make_pair(x, T()))).first)).second

expression, as specified in the language specification. This, as you can see, involves default-constructing a temporary object of type `T`, copying it into a `std::pair` object, which is later copied (again) into the new element of the map (assuming it wasn't there already). Obviously, this will produce a few intermediate `T` objects. 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.

Problem

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.)

Original source