I am aware of 5 general categories where recompiling a C++03 compiler as C++11 can cause unbounded performance increases that are practically unrelated to quality of implementation. These are all variations of move semantics.

std::vector reallocate

struct bar{ std::vector<int> data; }; std::vector<bar> foo(1); foo.back().data.push_back(3); foo.reserve(10); // two allocations and a delete occur in C++03

every time the foo 's buffer is reallocated in C++03 it copied every vector in bar .

In C++11 it instead moves the bar::data s, which is basically free.

In this case, this relies on optimizations inside the std container vector . In every case below, the use of std containers is just because they are C++ objects that have efficient move semantics in C++11 "automatically" when you upgrade your compiler. Objects that don't block it that contain a std container also inherit the automatic improved move constructors.

NRVO failure

When NRVO (named return value optimization) fails, in C++03 it falls back on copy, on C++11 it falls back on move. Failures of NRVO are easy:

std::vector<int> foo(int count){ std::vector<int> v; // oops if (count<=0) return std::vector<int>(); v.reserve(count); for(int i=0;i<count;++i) v.push_back(i); return v; }

or even:

std::vector<int> foo(bool which) { std::vector<int> a, b; // do work, filling a and b, using the other for calculations if (which) return a; else return b; }

We have three values -- the return value, and two different values within the function. Elision allows the values within the function to be 'merged' with the return value, but not with each other. They both cannot be merged with the return value without merging with each other.

The basic issue is that NRVO elision is fragile, and code with changes not near the return site can suddenly have massive performance reductions at that spot with no diagnostic emitted. In most NRVO failure cases C++11 ends up with a move , while C++03 ends up with a copy.

Returning a function argument

Elision is also impossible here:

std::set<int> func(std::set<int> in){ return in; }

in C++11 this is cheap: in C++03 there is no way to avoid the copy. Arguments to functions cannot be elided with the return value, because the lifetime and location of the parameter and return value is managed by the calling code.

However, C++11 can move from one to the other. (In a less toy example, something might be done to the set ).

push_back or insert

Finally elision into containers does not happen: but C++11 overloads rvalue move insert operators, which saves copies.

struct whatever { std::string data; int count; whatever( std::string d, int c ):data(d), count(c) {} }; std::vector<whatever> v; v.push_back( whatever("some long string goes here", 3) );

in C++03 a temporary whatever is created, then it is copied into the vector v . 2 std::string buffers are allocated, each with identical data, and one is discarded.

In C++11 a temporary whatever is created. The whatever&& push_back overload then move s that temporary into the vector v . One std::string buffer is allocated, and moved into the vector. An empty std::string is discarded.

Assignment

Stolen from @Jarod42's answer below.

Elision cannot occur with assignment, but move-from can.

std::set<int> some_function(); std::set<int> some_value; // code some_value = some_function();

here some_function returns a candidate to elide from, but because it is not used to construct an object directly, it cannot be elided. In C++03, the above results in the contents of the temporary being copied into some_value . In C++11, it is moved into some_value , which basically is free.

For the full effect of the above, you need a compiler that synthesizes move constructors and assignment for you.

MSVC 2013 implements move constructors in std containers, but does not synthesize move constructors on your types.

So types containing std::vector s and similar do not get such improvements in MSVC2013, but will start getting them in MSVC2015.