C++ – Pass by value or reference, to a C++ constructor that needs to store a copy

c++constructoroptimizationpass-by-referencepass-by-value

Should a C++ (implicit or explicit) value constructor accept its parameter(s) by value or reference-to-const, when it needs to store a copy of the argument(s) in its object either way?

Here is the shortest example I can think of:

struct foo {
    bar _b;
    foo(bar [const&] b) // pass by value or reference-to-const?
        : _b(b) { }
};

The idea here is that I want to minimize the calls to bar's copy constructor when a foo object is created, in any of the various ways in which a foo object might get created.

Please note that I do know a little bit about copy elision and (Named) Return Value Optimization, and I have read "Want Speed? Pass by Value", however I don't think the article directly addresses this use case.

Edit: I should be more specific.

Assume that I can't know the sizeof(bar), or whether or not bar is a fundamental, built-in type (bar may be a template parameter, and foo may be a class template instead of a class). Also, don't assume that foo's constructor can be inlined (or bar's, for that matter). Do assume that I at least might be using a compiler that implements RVO.

What I would like is for there to be a possibility (given compiler optimizations) that a call like this will invoke no calls to bar's copy constructor whatsoever (even when executing _b(b) in foo's initialization list):

foo f = function_that_creates_and_returns_a_bar_object_using_rvo();

Is there any possibility (given the C++98 standard) that this can be done, and if so, is it more or less likely to work if foo accepts its parameter by reference-to-const instead of by value?

Best Solution

In C++98 and C++03, you should pass const& bar and then copy. In C++0x, you should pass bar and then do a move (provided bar has a move constructor).

#include <utility>

struct foo
{
    bar _b;

    foo(bar b) : _b(std::move(b)) {}
};

If you construct foo with an lvalue parameter, the copy constructor will be called to create a copy b, and that copy will be moved into _b. If you construct foo with an rvalue parameter, bar's move constructor will be called to move into b, and then it will be moved again into _b.