Почему мы не можем использовать семантику перемещения, применяемую только для передачи по значению, а не для ссылки на постоянное значение? - PullRequest
0 голосов
/ 13 октября 2019

Здесь - это статья, которую я использую в качестве ссылки, которая в конечном итоге была упомянута в этом SO-ответе .

Автор приводит два примера:

Пример 1:

std::vector<std::string> 
sorted(std::vector<std::string> names)
{
    std::sort(names);
    return names;
}

// names is an lvalue; a copy is required so we don't modify names
std::vector<std::string> sorted_names1 = sorted( names );

// get_names() is an rvalue expression; we can omit the copy!
std::vector<std::string> sorted_names2 = sorted( get_names() );

Пример 2:

std::vector<std::string> 
sorted2(std::vector<std::string> const& names) // names passed by reference
{
    std::vector<std::string> r(names);        // and explicitly copied
    std::sort(r);
    return r;
}

Тогда говорят:

Хотя отсортированные и отсортированные2 на первый взгляд кажутся идентичными,Там может быть огромная разница в производительности, если компилятор копирует elision. Даже если фактическим аргументом для sorted2 является rvalue, источником копии, names, является lvalue, поэтому копия не может быть оптимизирована. В некотором смысле, elision copy является жертвой отдельной модели компиляции: внутри тела sorted2 нет информации о том, является ли фактический аргумент функции r-значением;снаружи, на сайте вызова, нет никаких признаков того, что копия аргумента в конечном итоге будет сделана.

Мой вопрос прост: почему компилятор не может использовать elision для копирования во втором примере, но он можетв первом?

А как насчет передачи по значению, а отличий их отличает? names названо в обоих случаях, поэтому я предполагаю, что мы также создаем lvalue в обоих случаях.

1 Ответ

0 голосов
/ 13 октября 2019

Разница в том, что names изменяемый объект или нет. Ссылка const lvalue не может быть изменена.


, поскольку get_names () является значением r, мы можем использовать семантику перемещения.

Не всегда. Рассмотрим, когда вызывается конструктор перемещения.

Однако, если параметр является ссылкой на постоянное значение, мы должны «сохранить» значение как значение l, чтобы не происходило простого переключения указателей

Когда параметр является ссылкой на lvalue, вы можете изменить объект. Однако вы не можете передать rvalue.

std::vector<std::string> 
sorted3(std::vector<std::string>& names)
{
    std::sort(names);
    return names;
}

// names is an lvalue; lvalue reference can bind lvalue. argument will be modified after execution `sorted3`.
std::vector<std::string> sorted_names1 = sorted3( names );

// get_names() is an rvalue expression; we cannot bind by lvalue reference.
//std::vector<std::string> sorted_names2 = sorted3( get_names() );

const lvalue ссылка может связать rvalue. Однако вы не можете изменить объект так, чтобы не происходило простого переключения указателей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...