Can someone help me to understand how the std::map container is implemented? I have an class that contains atomic members and I have no need to invoke a copy constructor so I use the c++11 delete operator to suppress implicit generation of the copy constructor.
MyCalss(const MyClass& a) = delete; This has worked fine with my windows build, however in Linux I am greeted with an error informing me that the [] operator of the std::map class is trying to invoke a deleted function.
There seems to be a major difference between the Windows VS2013 and Linux GCC 4.7.x implementations of map. This led me to do an experiment regarding how an object is inserted into a map.
I wrote this small example program:
#include <stdlib.h> #include <stdio.h> #include <map> #include <iostream> #include <string> using namespace std; class TestItem { public: TestItem () { _name = "TestItem" + id(); cout << "Constructing " << _name << endl; } TestItem (const TestItem & other) { _name = "TestItem " + id(); cout << "Copying " << other._name << " to new " << _name <<endl; } string id() { static int id = 0; char buf[2]; sprintf_s(buf, "%d", id++); return string(buf); } ~TestItem(){ cout << "Destroying " << _name << endl; } void doStuff() { // stub } string _name; }; void run() { cout << "making new obj" << endl; TestItem a; cout << endl << endl; map<string, TestItem> TestItemMap; cout << "Makeing new obj as part of a map insert" << endl; TestItemMap["foo"].doStuff(); cout << endl << endl; cout << "adding a value to the map" << endl; TestItemMap["new foo key"] = a; cout << endl << endl; cout << "looking up a value that has already been inserted" << endl; TestItem& b = TestItemMap["foo"]; cout << endl << endl; } int main(int argc, char** argv) { run(); } In Windows when I run this program I get the following output:
making new obj Constructing TestItem0 Making new obj as part of a map insert Constructing TestItem1 adding a value to the map Constructing TestItem2 looking up a value that has already been inserted Destroying TestItem1 Destroying TestItem0 Destroying TestItem0 This is what I would expect to see, internally when I write
TestItemMap["foo"].doStuff(); I would expect that map would create a new instance of TestItem and then insert it in to the RedBlack Tree by internally linking the tree node to the new TestItem.
However when I run this same code in Linux the results are very different
making new obj Constructing TestItem0 Making new obj as part of a map insert Constructing TestItem1 Copying TestItem1 to new TestItem2 Copying TestItem2 to new TestItem3 Destroying TestItem2 Destroying TestItem1 adding a value to the map Constructing TestItem4 Copying TestItem4 to new TestItem5 Copying TestItem5 to new TestItem6 Destroying TestItem5 Destroying TestItem4 looking up a value that has already been inserted Destroying TestItem0 Destroying TestItem3 Destroying TestItem0 This would indicate to me that the [] operator is creating a new instance of TestItem then calling the external map.insert() function and then destroying the newly created TestItem, and that only explains one of the calls to the copy constructor. Is the c++ stdlib in gcc really this inefficient?
Is there some standard trick that people use to overcome this problem?
TestItem0is destroyed.TestItemMap["new mooky key"] = a;, which I bet the OP didn't see coming.