Я пытаюсь выяснить, как 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, конструкторы копирования не вызываются. В противном случае эти функции (которые получают ссылку в качестве параметра) по-прежнему вызывают конструкторы копирования.
Зависит ли эта функция от компилятора? Я делаю что-то неправильно?
m14 = fChangeClassRetRef(m11);
-> Copy Assignment Operator
Функция возвращает ссылку (lvalue), она не может выполнять перемещение-присваивание, поскольку аргумент не является rvalue.
m14 = fChangeClassRetValue(m11);
-> Copy Constructor
-> C++11 Move Operator
Конструктор копирования запускается изнутри, чтобы создать возвращаемое значение. Это должен быть конструктор копирования, а не конструктор перемещения, поскольку аргумент является ссылкой (lvalue). Присвоение возвращаемого значения m14
использует оператор присваивания перемещения, поскольку аргумент является значением r.
У тебя есть:
// 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, но не в этом случае.) Следовательно, нельзя вызвать конструктор перемещения и вызвать конструктор копирования.