go to start Ex W2
|home |print view |recent changes |changed March 4, 2016 |
exact
|You are 54.81.139.56 <- set your identity!

Sections: Tracer Again | Tracer in Standard Container | Copy Assignment | Move Construction/Assignment | Vector Again | Moving vs. Copying Large Objects |

Tracer Again ^

From CPlusPlus you might already be familiar with the tracer class as used in the extra exercises. Today it's not extra anymore.

#include <iostream>
#include <string>

struct Tracer {
	explicit Tracer(std::string name = "") :  name { name } {
		std::cout << "Tracer created: " << name << std::endl;
	}
	~Tracer() {
		std::cout << "Tracer destroyed: " << name << std::endl;
	}
	Tracer(Tracer const& other) : name { other.name + " copy" } {
		std::cout << "Tracer copied: " << name << std::endl;
	}
	void show() const {
		std::cout << "Tracer: " << name << std::endl;
	}
	std::string name;
};

void foo(Tracer t) {
	Tracer trace("foo");
	t.show();
}

Tracer bar(Tracer const &t) {
	Tracer trace("bar");
	t.show();
	return trace;
}

int main() {
	Tracer m { "main" };
	{
		Tracer inner { "inner" };
		foo(inner);
		auto trace = bar(inner);
		trace.show();
		inner.show();
	}
	foo(Tracer { "temp" });
	m.show();
}

Tracer in Standard Container ^

Observe the behavior of the Tracer type when used in an std::vector.

  std::vector<Tracer> v{};
  v.push_back(Tracer{"T1"});
  v.push_back(Tracer{"T2"});
  v.push_back(Tracer{"T3"});
  v.push_back(Tracer{"T4"});

  std::vector<Tracer> v_copy{v};

Copy Assignment ^

Your Tracer type does not provide an assignment operator. Add one which adds with " copy-assigned" to the name, similar to the implemented constructors..

int main() {
  ...
  std::cout << "\t\t--- creating sink and source ----" << std::endl;
  Tracer sink {"sink"}, source {"source"};

  std::cout << "\t\t--- assigning source to sink ----" << std::endl;
  sink = source;

  std::cout << "\t\t--- showing sink ----" << std::endl;
  sink.show();

  std::cout << "\t\t--- showing source ----" << std::endl;
  source.show();

  std::cout << "\t\t--- end of main ----" << std::endl;
}

Move Construction/Assignment ^

Replace the copy constructor and copy-assignment operator of the tracer class with a move constructor and a move-assignment operator. Within the move constructor change the parameter object's name to name+"moved from" and define the name of the moved-to object to be the other's original name.

What about the state of source after the move assignment?

As you have a moveable type what happens if you just call std::move on a tracer object? What is the output of the call below? Why?

int main() {
  ...
  std::cout << "\t\t--- std::move(m) ----" << std::endl;
  std::move(m);
  std::cout << "\t\t--- end of main ----" << std::endl;
}

Vector Again ^

Now as your Tracer is movable:

Moving vs. Copying Large Objects ^

Large objects can benefit from move operations. An std::vector, for example, allocates memory on the heap for storing its values. Copying a vector requires additional heap space and copies all values to this new memory location. Moving a vector just needs to move the pointers, which access this memory, to the move-constructed/assigned vector.

Try to measure the difference in allocating, copying and moving a large std::vector.

You can use std::chrono to measure the operations.

  auto start = std::chrono::system_clock::now();
  //allocate large vector
  std::chrono::duration<double> delta = std::chrono::system_clock::now() - start;
  std::cout << "creating the container took: " << delta.count() << "s time\n";

What size of vector is large enough to observe the behavior?


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

Ex W2
go to start