It often doesn't happen because it doesn't need to happen. This is called copy elision. In many cases, the function doesn't need to make copies, so the compiler optimizes them away. For example, with the following function:
big_type foo(big_type bar)
{
return bar + 1;
}
big_type a = foo(b);
Will get converted to something like:
void foo(const big_type& bar, big_type& out)
{
out = bar + 1;
}
big_type a;
foo(b, a);
The removal of the return value is called the "Return Value Optimization" (RVO), and is implemented by most compilers, even when optimizations are turned off!