Существуют разные способы оптимизации кода, который есть у вас, но ссылки на значения не совпадают.Проблема в том, что ни A
, ни B
не могут быть перемещены бесплатно, поскольку вы не можете украсть содержимое объекта.Рассмотрим следующий пример:
template <typename T>
class simple_vector {
typedef T element_type;
typedef element_type* pointer_type;
pointer_type first, last, end_storage;
public:
simple_vector() : first(), last(), end_storage() {}
simple_vector( simple_vector const & rhs ) // not production ready, memory can leak from here!
: first( new element_type[ rhs.last - rhs.first ] ),
last( first + rhs.last-rhs.first ),
end_storage( last )
{
std::copy( rhs.first, rhs.last, first );
}
simple_vector( simple_vector && rhs ) // we can move!
: first( rhs.first ), last( rhs.last ), end_storage( rhs.end_storage )
{
rhs.first = rhs.last = rhs.end_storage = 0;
}
~simple_vector() {
delete [] rhs.first;
}
// rest of operations
};
В этом примере, когда ресурсы удерживаются с помощью указателей, существует простой способ перемещения объекта (т.е. кража содержимого старого объекта).в новый и оставляя старый объект в разрушаемом, но бесполезном состоянии. Просто скопируйте указатели и сбросьте их в старом объекте в ноль, чтобы деструктор исходного объекта не освободил память.
Проблема сA
и B
означают, что фактическая память удерживается в объекте через массив, и этот массив не может быть перемещен в другое место памяти для нового C
object.
Конечно, поскольку вы используете выделенные в стеке объекты в коде, старый (N) RVO может использоваться компилятором, а когда вы делаете: C c = { create_a(), create_b() };
компилятор может выполнить эту оптимизацию(в основном установите атрибут c.a
для адреса возвращаемого объекта из create_a
, в то время как при компиляции create_a
создайте возвращенный временный объект непосредственно oТаким же адресом, так эффективно, c.a
, возвращенный объект из create_a
и временный объект, созданный внутри create_a
(неявный this
для конструктора) являются одним и тем же объектом, исключая две копии,То же самое можно сделать с c.b
, избегая затрат на копирование.Если компилятор встроит ваш код, он удалит create_c
и заменит его конструкцией, аналогичной: C c = {create_a(), create_b()};
, так что он может потенциально оптимизировать удаление всех копий.
С другой стороны, обратите внимание, что эта оптимизацияне может быть полностью использован в случае объекта C
, выделенного динамически, как в C* p = new C; p->a = create_a();
, так как назначение , а не в стеке, компилятор может только оптимизировать временное внутреннее create_a
и его возвратзначение, но оно не может совпадать с p->a
, поэтому необходимо сделать копию.В этом преимущество rvalue-reference перед (N) RVO, но, как упоминалось ранее, вы не можете эффективно использовать rvalue-reference в своем примере кода напрямую.