User Tools

Site Tools


notes:stl_allocation_example

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
notes:stl_allocation_example [2013/02/25 16:58]
andy
notes:stl_allocation_example [2013/02/25 17:31]
andy
Line 89: Line 89:
  
 ==== Typical output ==== ==== Typical output ====
 +
 +The output below demonstrates that an instance is first constructed in-place on the stack (the expression ''​MyClass(11)''​ does this, for example). Then, the ''​std::​list''​ code uses [[wikipedia>​placement new]] to copy the item into place, which results in the copy constructor being invoked (assuming that placement new itself isn't overridden). Finally, the destructor of the in-place instance on the stack is invoked.
  
 <​file>​ <​file>​
Line 128: Line 130:
 </​file>​ </​file>​
  
-===== std::map =====+===== std::​map ​(assignment) ​=====
  
-<code cpp stl_copy_map.cpp>+There are multiple ways to insert an item into a ''​std::​map''​ with subtly different memory copying behaviour. The code below shows a simple approach using assignment and array indexing syntax. 
 + 
 +<code cpp stl_copy_map_assign.cpp>
 #include <map> #include <map>
 #include <​stdio.h>​ #include <​stdio.h>​
Line 224: Line 228:
  
 ==== Typical Output ==== ==== Typical Output ====
 +
 +In contrast with the [[#​std::​list]] example above, ''​std::​map''​ invokes a substantial number of copy operations in the process of adding an element via assignment, as is done above.
 +
 +First, an in-place instance is constructed on the stack in response to the expression ''​MyClass(11)''​ as was done for ''​std::​list''​. Next, the default constructor is called to instantiate the instance in the map on the left-hand side of the assignment, and [[wikipedia>​placement new]] is used to copy this into the map --- there are two copies, presumably one being the creation of the ''​std::​pair''​ object to hold the key and value and the other to copy this again into the actual storage. At this point the destructors of both temporary instances are invoked. Then the assignment operator is used to overwrite the value in the map with the in-place instance created earlier. Finally, the destructor for the in-place instance is called, as with ''​std::​list''​.
  
 <​file>​ <​file>​
Line 281: Line 289:
 0x1edb0c4: ~MyClass(22) 0x1edb0c4: ~MyClass(22)
 0x1edb094: ~MyClass(21) 0x1edb094: ~MyClass(21)
 +</​file>​
 +
 +===== std::map (insert) =====
 +
 +As an alternative to using assignment, the ''​insert()''​ method can be used instead. This has the advantage that the class does not require a default constructor.
 +
 +<code cpp stl_copy_map_insert.cpp>​
 +#include <map>
 +#include <​stdio.h>​
 +
 +class MyClass
 +{
 +public:
 +  MyClass(int id);
 +  MyClass(const MyClass &​other);​
 +  ~MyClass();
 +  MyClass&​ operator=(const MyClass &​other);​
 +  int getID() const { return myID; }
 +private:
 +  MyClass();
 +  int myID;
 +};
 +
 +MyClass::​MyClass() : myID(-1)
 +{
 +  printf("​%p:​ MyClass()\n",​ this);
 +}
 +
 +MyClass::​MyClass(int id) : myID(id)
 +{
 +  printf("​%p:​ MyClass(%d)\n",​ this, myID);
 +}
 +
 +MyClass::​MyClass(const MyClass &other) : myID(other.myID)
 +{
 +  printf("​%p:​ MyClass(%p: MyClass(%d))\n",​ this, &other, myID);
 +}
 +
 +MyClass::​~MyClass()
 +{
 +  printf("​%p:​ ~MyClass(%d)\n",​ this, myID);
 +}
 +
 +MyClass&​ MyClass::​operator=(const MyClass &other)
 +{
 +  myID = other.myID;
 +  printf("​%p:​ MyClass = %p: MyClass(%d)\n",​ this, &other, myID);
 +
 +  return *this;
 +}
 +
 +
 +int main()
 +{
 +  std::​map<​int,​ MyClass> one;
 +  std::​map<​int,​ MyClass> two;
 +
 +  printf("​Adding 11 to one\n"​);​
 +  one.insert(std::​make_pair(11,​ MyClass(11)));​
 +  printf("​Adding 12 to one\n"​);​
 +  one.insert(std::​make_pair(12,​ MyClass(12)));​
 +  printf("​Adding 21 to two\n"​);​
 +  two.insert(std::​make_pair(21,​ MyClass(21)));​
 +  printf("​Adding 22 to two\n"​);​
 +  two.insert(std::​make_pair(22,​ MyClass(22)));​
 +
 +  printf("​Contents of one:​\n"​);​
 +  for (std::​map<​int,​ MyClass>::​iterator it = one.begin();​
 +       it != one.end(); ++it) {
 +    printf(" ​ %d: %d\n", it->​first,​ it->​second.getID());​
 +  }
 +  printf("​Contents of two:​\n"​);​
 +  for (std::​map<​int,​ MyClass>::​iterator it = two.begin();​
 +       it != two.end(); ++it) {
 +    printf(" ​ %d: %d\n", it->​first,​ it->​second.getID());​
 +  }
 +
 +  printf("​Calling one.swap(two)\n"​);​
 +  one.swap(two);​
 +
 +  printf("​Contents of one:​\n"​);​
 +  for (std::​map<​int,​ MyClass>::​iterator it = one.begin();​
 +       it != one.end(); ++it) {
 +    printf(" ​ %d: %d\n", it->​first,​ it->​second.getID());​
 +  }
 +  printf("​Contents of two:​\n"​);​
 +  for (std::​map<​int,​ MyClass>::​iterator it = two.begin();​
 +       it != two.end(); ++it) {
 +    printf(" ​ %d: %d\n", it->​first,​ it->​second.getID());​
 +  }
 +
 +  printf("​Clearing two\n"​);​
 +  two.clear();​
 +
 +  printf("​Exiting now\n"​);​
 +  return 0;
 +}
 +
 +</​code>​
 +
 +==== Typical output ====
 +
 +This approach requires one fewer operation than the assignment-based creation above. After the in-place instance is constructed,​ it is immediately copied via the copy constructor into the ''​std::​pair''​ and then again into the storage within the map. All three temporary instances are then deleted.
 +
 +<​file>​
 +Adding 11 to one
 +0x7fffc2b75f80:​ MyClass(11)
 +0x7fffc2b75eb4:​ MyClass(0x7fffc2b75f80:​ MyClass(11))
 +0x7fffc2b75ec4:​ MyClass(0x7fffc2b75eb4:​ MyClass(11))
 +0xdaa034: MyClass(0x7fffc2b75ec4:​ MyClass(11))
 +0x7fffc2b75ec4:​ ~MyClass(11)
 +0x7fffc2b75eb4:​ ~MyClass(11)
 +0x7fffc2b75f80:​ ~MyClass(11)
 +Adding 12 to one
 +0x7fffc2b75f90:​ MyClass(12)
 +0x7fffc2b75ed4:​ MyClass(0x7fffc2b75f90:​ MyClass(12))
 +0x7fffc2b75ee4:​ MyClass(0x7fffc2b75ed4:​ MyClass(12))
 +0xdaa064: MyClass(0x7fffc2b75ee4:​ MyClass(12))
 +0x7fffc2b75ee4:​ ~MyClass(12)
 +0x7fffc2b75ed4:​ ~MyClass(12)
 +0x7fffc2b75f90:​ ~MyClass(12)
 +Adding 21 to two
 +0x7fffc2b75fa0:​ MyClass(21)
 +0x7fffc2b75ef4:​ MyClass(0x7fffc2b75fa0:​ MyClass(21))
 +0x7fffc2b75f04:​ MyClass(0x7fffc2b75ef4:​ MyClass(21))
 +0xdaa094: MyClass(0x7fffc2b75f04:​ MyClass(21))
 +0x7fffc2b75f04:​ ~MyClass(21)
 +0x7fffc2b75ef4:​ ~MyClass(21)
 +0x7fffc2b75fa0:​ ~MyClass(21)
 +Adding 22 to two
 +0x7fffc2b75fb0:​ MyClass(22)
 +0x7fffc2b75f14:​ MyClass(0x7fffc2b75fb0:​ MyClass(22))
 +0x7fffc2b75f24:​ MyClass(0x7fffc2b75f14:​ MyClass(22))
 +0xdaa0c4: MyClass(0x7fffc2b75f24:​ MyClass(22))
 +0x7fffc2b75f24:​ ~MyClass(22)
 +0x7fffc2b75f14:​ ~MyClass(22)
 +0x7fffc2b75fb0:​ ~MyClass(22)
 +Contents of one:
 +  11: 11
 +  12: 12
 +Contents of two:
 +  21: 21
 +  22: 22
 +Calling one.swap(two)
 +Contents of one:
 +  21: 21
 +  22: 22
 +Contents of two:
 +  11: 11
 +  12: 12
 +Clearing two
 +0xdaa064: ~MyClass(12)
 +0xdaa034: ~MyClass(11)
 +Exiting now
 +0xdaa0c4: ~MyClass(22)
 +0xdaa094: ~MyClass(21)
 </​file>​ </​file>​
  
notes/stl_allocation_example.txt · Last modified: 2013/02/25 17:31 by andy