Передача по значению или универсальная ссылка
Я хочу разработать небольшой полиморфный класс со стиранием типов, и мне интересно, какая версия шаблонного конструктора лучше и должна использоваться.
Мы можем передать по значению:
class A
{
...
template< typename T >
A( T t ) { /* create the underlying model via std::move */ }
...
};
или мы можем использовать универсальную ссылку:
class A
{
...
template< typename T >
A( T &&t ) { /* create the underlying model via std::forward */ }
...
};
(Универсальная ссылка должна быть включена, если для случая, когда T
это не сам класс и класс не копируется). Есть идеи? Обе версии выглядят одинаково для меня.
1 ответ
Они не эквивалентны, и иногда одно желательно по сравнению с другим. Звездный разговор Николая Йосуттиса - это час разговора об этом. Я настоятельно рекомендую посмотреть его хотя бы один раз.
Лично, если только вы не столкнетесь с особым случаем, когда преобразования стоят дорого, и вы хотите максимально избежать временных затрат, я бы предложил просто передать по значению и std::move
спор.
Случай где T&&
более эффективно:
struct foo {
std::string bar;
template <typename T>
foo(T&& t)
:bar(std::forward<T>(t)){}
};
против:
struct foo {
std::string bar;
foo(std::string t)
:bar(std::move(t)){}
};
когда вы делаете:
int main() {
foo f("some char*");
}
В первом случае (совершенная пересылка) вы просто создаете std::string
с const char*
аргумент. Во втором случае вы создаете один временный (t
от "some char*"
) и один пустой std::string
объект, затем вы применяете одну операцию перемещения. Это не конец света, но первая версия просто более эффективна.
Чтобы быть абсолютно ясно о производительности:
Первая версия использует 1 распределение
вторая версия использует 1 распределение и 1 ход
и под ходом я не имею в виду std::move
, поскольку он не генерирует код (это просто приведение). Под движением я подразумеваю код, который должен быть выполнен, который фактически перемещается из строки, которая является частьюstd::string(std::string&&)
,
Еще раз - приведенный выше пример был основан на разговоре, который я связал в начале ответа. Это действительно стоит посмотреть.