go to start Sol W2
|home |print view |recent changes |changed March 1, 2017 |
exact
|You are 54.81.139.56 <- set your identity!

Sections: Expected Observations for the Tracer Assignment | Tracer in Standard Container | Observing the =[push_back]= Operations | Copying the vector | Copy-Assignment | Move Operations | Vector Again | Moving vs. Copying Large Objects |

Expected Observations for the Tracer Assignment ^

Tracer in Standard Container ^

Observing the push_back Operations ^

At a glance, when checking the output of the four push_back operations there are more copies than expected. Especially, T1 is copied several (three in my case) times. These copies happen when adding elements to a vector that has reached the capacity of the array used to store the elements. When this happens a new (bigger) array is allocated and all elements are copied to this new array. The old array is then deallocated.

Below is an excerpt from the output to show this behavior. It is generated by the v.push_back(Tracer{"T2"}) statement.

Tracer created: T2           (1)
Tracer copied: T2 copy       (2)
Tracer copied: T1 copy copy  (3)
Tracer destroyed: T1 copy    (4)
Tracer destroyed: T2         (5)

Copying the vector ^

The result of copying the vector is straight-forward. Every element of the vector is copied again.

Tracer copied: T1 copy copy copy copy
Tracer copied: T2 copy copy copy
Tracer copied: T3 copy copy
Tracer copied: T4 copy copy

Copy-Assignment ^

The implementation of the copy-assignment operator is as follows:

Tracer & operator=(Tracer const & rhs) {
  name = rhs.name + " copy-assigned";
  std::cout << "Tracer copy-assigned: " << name << std::endl;
  return *this;
}

Move Operations ^

The copy-constructor and the copy-assignment operator are replaced by the following implementations of the move-constructor and the move-assignment operator:

Tracer(Tracer && other) :
  name { other.name + " moved from" } {
  other.name = "";
  std::cout << "Tracer moved: " << name << std::endl;
}

Tracer & operator=(Tracer && rhs) {
  std::swap(name, rhs.name);
  name += " moved from";
  std::cout << "Tracer move-assigned: " << name << std::endl;
  return *this;
}

#include <utility>
...
foo(std::move(inner));
...
std::vector<Tracer> v_copy { std::move(v) };
...
sink = std::move(source);

Vector Again ^

When adding Tracers to the vector the copy operations are just replaced by the corresponding move operations. But, there is a change when moving the vector to another vector! This operation does not have any effect on the contained Tracer objects at all! Because they are left in the same memory location no additional move operation happens.

Moving vs. Copying Large Objects ^

It takes some elements to observe a timing difference between copy and move operations. But even on fast computers when copying or moving 1GB of data the difference should be measurable. If you cannot see the difference at any size, check whether you have enabled some kind of optimization in your compiler that eliminates the operations you are trying to measure completely.


|home |print view |recent changes |changed March 1, 2017 |
exact
|You are 54.81.139.56 <- set your identity!

Sol W2
go to start