Оптимизация RVO и NRVO + оператор перемещения C ++ 11

Я пытаюсь выяснить, как RVO и NRVO работают вместе с новыми операторами перемещения C ++ 11.
Я набросал фиктивный класс с несколькими примерами.

РЕДАКТИРОВАТЬ: отображается только наиболее важная часть кода.

Полный исходный код доступен Вот.

У меня есть две функции, которые получают класс в качестве ссылки и возвращают либо значение, либо ссылку:

VOpt& fChangeClassRetRef(VOpt &m) {
m.setX(21);
return m;
}

VOpt fChangeClassRetValue(VOpt &m) {
m.setX(21);
return m;
}

Когда я вызываю эти функции, я получаю следующее:

VOpt &m14 = fChangeClassRetRef(m13);

m14 = fChangeClassRetRef(m11);
-> Copy Assignment Operator

m14 = fChangeClassRetValue(m11);
-> Copy Constructor
-> C++11 Move Operator

Когда используется ссылка lvalue, конструкторы копирования не вызываются. В противном случае эти функции (которые получают ссылку в качестве параметра) по-прежнему вызывают конструкторы копирования.

Зависит ли эта функция от компилятора? Я делаю что-то неправильно?

0

Решение

m14 = fChangeClassRetRef(m11);
-> Copy Assignment Operator

Функция возвращает ссылку (lvalue), она не может выполнять перемещение-присваивание, поскольку аргумент не является rvalue.

m14 = fChangeClassRetValue(m11);
-> Copy Constructor
-> C++11 Move Operator

Конструктор копирования запускается изнутри, чтобы создать возвращаемое значение. Это должен быть конструктор копирования, а не конструктор перемещения, поскольку аргумент является ссылкой (lvalue). Присвоение возвращаемого значения m14 использует оператор присваивания перемещения, поскольку аргумент является значением r.

3

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

У тебя есть:

// Change the value of the class, return ref!
VOpt& fChangeClassRetRef(VOpt &m) {
m.setX(21);
return m; //#1
}

который был использован таким образом:

// VOpt m11;
VOpt m12 = fChangeClassRetRef(m11); // #2

Давайте проанализируем: #1 возвращает имя аргумента (не локальной переменной), поэтому ни RVO, ни NRVO здесь не применяются. Сейчас fChangeClassRetRef возвращает ссылку куда угодно m связан, который в # 2 является m11, Поэтому мы инициализируем m12 со ссылкой на lvalue m11, В этом случае он не может вызвать конструктор перемещения, потому что он принимает значение r, и, как мы только что видели, вы предоставляете значение lvalue. Конструктор копирования вызывается.

Другой случай аналогичен. У тебя есть

VOpt fChangeClassRetValue(VOpt &m) {
m.setX(21);
return m;
}

который называется так:

// VOpt m13;
VOpt &m14 = fChangeClassRetRef(m13);

Как и выше, здесь нет ни RVO, ни NRVO, потому что вы возвращаете имя аргумента.

Функция возвращает значение, а вы возвращаете lvalue. (В некоторых обстоятельствах компиляторам разрешается обрабатывать возвращаемое значение lvalue, как если бы оно было значением rvalue, но не в этом случае.) Следовательно, нельзя вызвать конструктор перемещения и вызвать конструктор копирования.

1

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