Будут ли компиляторы автоматически применять семантику перемещения в методе установки?

Я хочу знать, разрешено ли компилятору автоматически использовать конструктор перемещения для wstring в следующем методе установки (без явного вызова std :: move):

void SetString(std::wstring str)
{
m_str = str;  // Will str be moved into m_str automatically or is std::move(str) needed?
}

Из того, что я прочитал, звучит так, как будто компилятору не разрешено принимать это решение, поскольку str является lvalue, но кажется вполне очевидным, что использование move здесь не изменит поведение программы.

Запрет на перемещение, будет ли применен какой-либо другой тип копирования?

4

Решение

[is] компилятору […] разрешено автоматически использовать конструктор перемещения

Да, это было бы хорошо. Но это не только оптимизация, это реально влияет на язык.

Рассмотрим тип перемещения только как unique_ptr:

std::unique_ptr<int> f()
{
std::unique_ptr<int> up;
return up; // this is ok although unique_ptr is non-copyable.
}

Давайте предположим, что ваше правило будет включено в стандарт C ++, называемое правилом «последнего вхождения аргумента».

void SetString(std::unique_ptr<int> data)
{
m_data = data; // this must be ok because this is "argument's last occurence"}

Проверить, используется ли идентификатор при возврате, легко. Проверка, является ли это «последним случаем аргумента», не является.

void SetString(std::unique_ptr<int> data)
{
if (condition) {
m_data = data; // this is argument's last occurence
} else {
data.foo();
m_data = data; // this is argument's last occurence too
}
// many lines of code without access to data
}

Это тоже правильный код. Таким образом, каждый компилятор должен будет проверять «последнее вхождение аргумента», что не так-то просто. Для этого ему нужно будет просмотреть всю функцию, чтобы решить, верна ли первая строка. Также трудно рассуждать как человек, если вам нужно прокрутить 2 страницы вниз, чтобы проверить это.

Нет, компилятор не разрешен в C ++ 11. И он, вероятно, не будет допущен в будущих стандартах, потому что эту функцию очень сложно реализовать в компиляторах в целом, и это просто удобство для пользователя.

3

Другие решения

нет, семантика перемещения здесь не будет использоваться, так как str может использоваться в следующем коде, фактически, даже если это было значение rvalue, вам все равно пришлось бы использовать std :: move force .. если вы хотите использовать семантику перемещения, я бы посоветовал получить wstring&& str к функции, а затем с помощью Move ..

1

Нет, компилятор не допускается. По ряду причин, а не только потому, что это сложно сделать. Я думаю, что копирование и перемещение могут иметь побочные эффекты, и вам нужно знать, когда можно ожидать, что каждый из них будет использован. Например, хорошо известно, что возвращение локального объекта переместит его — вы ожидаете, что это задокументировано, все в порядке.

Итак, у нас есть следующие возможности:

Ваш пример:

void SetString(std::wstring str)
{
m_str = str;
}

Для r-значений: один r-ref в strплюс копия в m_str, Для l-значений: копия в str копия в m_str,

Мы можем сделать это «лучше» вручную:

void SetString( std::wstring str)
{
m_str = std::move(str);
}

Для r-значений: один r-ref в strплюс переезд в m_str, Для l-значений: копия в str движение в m_str,

Если по какой-то причине (вы хотите, чтобы он компилировался без C ++ 11 без изменений, но автоматически использовали преимущества C ++ 11 при переносе кода?), Вам не нужно «вручную оптимизировать» код, который вы можете сделать:

void SetString(const std::wstring& str)
{
m_str = str;
}

Для значений r: один реф в strплюс копия в m_str, Для значений l: ссылка в str копия в m_str, Никогда 2 копии.

1
По вопросам рекламы [email protected]