В С++ 11 мы в некоторых случаях ориентируемся на передачу объектов по значению, а в других - на const-reference. Однако это руководство зависит от реализации метода, а не только от его интерфейса и предполагаемого использования его клиентами.
Когда я пишу интерфейс, я не знаю, как он будет реализован. Есть ли хорошее правило для написания сигнатур методов? Например, в следующем фрагменте кода следует использовать Bar1 или Bar2?
class IFoo
{
public:
    virtual void Bar1(std::string s) = 0;
    virtual void Bar2(const std::string& s) = 0;
};
Вы можете перестать читать здесь, если согласитесь, что правильная подпись зависит от реализации. Вот пример, который показывает, почему я так считаю.
В следующем примере мы должны передать строку по значению:
class Foo
{
    std::string bar;
    Foo(std::string byValue)
        : bar(std::move(byValue))
    {
    }
};
Теперь мы можем эффективно создавать Foo во всех случаях:
Foo foo1("Hello world"); // create once, move once
Foo foo2(s); // the programmer wants to copy s. One copy and one move
Foo foo3(std::move(t)); // the programmer does not need t anymore. No copy at all
В других случаях мы предпочитаем передавать объекты по ссылке const. Например, в следующем случае мы никогда не хотим копировать/хранить аргумент, просто используйте его методы:
void DoStuff(const std::string& byRef)
{
    std::cout << byRef.length() << std::endl;
}
Все возможные способы использования вышеуказанного метода уже настолько эффективны, насколько это возможно.
Обновление
Я считаю, что забыл показать проблемы с альтернативой const-reference. Если вышеуказанный класс Foo был реализован следующим образом:
class Foo
{
    std::string bar;
    Foo(const std::string& byRef)
        : bar(byRef)
    {
    }
};
Тогда мы получили бы следующие результаты:
Foo foo1("Hello world"); // Here we would have one more copy of the string. It is less efficient.
Foo foo2(s);             // One copy, like before
Foo foo3(std::move(t));  // Irrelevant here.
Алекс.