Передача параметра в функцию с помощью std :: move, есть ли разница, если этот параметр объявлен как передаваемый по значению или с операндом перемещения &&? - PullRequest
1 голос
/ 30 октября 2019

Мне любопытно, есть ли какая-либо разница (для компилятора) между этими двумя. Единственная разница между ними заключается в том, что ValueClass принимает параметр в конструкторе по ссылке

#include <string>

class ValueClass
{
public:
    ValueClass(std::string obj) : m_obj(std::move(obj)) {}

private:
    std::string m_obj;
};

class MoveClass
{
public:
    MoveClass(std::string&& obj) : m_obj(std::move(obj)) {}

private:
    std::string m_obj;
};

void SomeFunc()
{
    std::string a, b;

    a = "a";
    b = "b";

    ValueClass c(std::move(a));
    MoveClass d(std::move(b));
}

Я быстро проверил goldbolt , и он действительно выглядитподобно тому, как вызов конструктора MoveClass приводит к меньшему количеству строк сборки (при условии, что godbolt точен и не приписывает какие-либо строки сборки неправильно).

Таким образом, мой вопрос становится таким: почему есть разница? Настраивает ли компилятор какое-то временное хранилище, в которое строка перемещается, а затем сразу же выходит из нее?

Теоретически это должно быть оптимизировано? В таком случае, являются ли различия исключительно для программиста наполнением сигнатуры функции большим значением и информацией, чтобы ее было легче понять тем, кто захочет ее вызвать?

1 Ответ

2 голосов
/ 30 октября 2019

ValueClass требует, чтобы конструктор перемещения std::string вызывался дважды: один раз для создания параметра obj, а затем для инициализации члена m_obj.

MoveClass требуется только одно перемещениеконструктор std::string, который нужно вызвать: obj является ссылкой (rvalue) на b (новый объект std::string здесь не создается). Только инициализация m_obj включает конструктор перемещения std::string.


По-прежнему остается вопрос, будет ли разрешено исключение любого из этих вызовов (как исключение из правила «как если»),Это не тот случай, хотя;ни инициализация элемента, ни инициализация параметра функции не являются допустимым контекстом для исключающих конструкторов (или временных): https://en.cppreference.com/w/cpp/language/copy_elision


Теперь, в данном коде, не обязательно есть побочные эффекты, которые требуют, чтобы компилятор сохраняллюбой из вызовов конструктора. Фактически, если вы не выполняете переназначение в main, gcc замечает, что вся программа не имеет побочных эффектов и может быть оптимизирована до неактивности.

https://godbolt.org/z/hxrVfC

Вы также не дали MSVC правильные параметры. Наивысшая оптимизация - /O2, а не -O3 (хотя -O2 работает). Обратите внимание на предупреждения компилятора!

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