Перегрузка на ссылке, по сравнению с единственной передачей значением + станд.:: переместиться?

Кажется, что основной совет относительно rvalues 0x C++ состоит в том, чтобы добавить конструкторов перемещения и переместить операторы в Ваши классы до реализации по умолчанию компиляторов их.

Но ожидание является проигрывающей стратегией при использовании VC10 потому что автоматическая генерация, вероятно, не будет здесь до VC10 SP1, или в худшем случае, VC11. Вероятно, ожидание этого будет измеряться в годах.

Здесь находится моя проблема. Написание всего этого дублирующего кода не является забавой. И неприятно посмотреть на. Но это - хорошо принятая нагрузка для тех классов, которые считают медленными. Не так для сотен, если не тысячи, меньших классов.

:: вздохи:: C++ 0x, как предполагалось, позволял мне написать меньше кода, не больше!

И затем у меня была мысль. Совместно использованный многими, я предположил бы.

Почему не только передают все значением? Не будет станд.:: переместитесь +, копируют elision, делают это почти оптимальным?

Пример 1 - Типичный конструктор Pre-0x

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // single copy
OurClass(SomeClass());  // single copy

Недостатки: потраченная впустую копия для rvalues.

Пример 2 - рекомендуемый C++ 0x?

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // zero copies, one move
OurClass(SomeClass());  // zero copies, one move

Профессионалы: По-видимому, самое быстрое.
Недостатки: много кода!

Пример 3 - Передача значением + станд.:: переместиться

OurClass::OurClass(SomeClass obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy, one move
OurClass(std::move(o)); // zero copies, two moves
OurClass(SomeClass());  // zero copies, one move

Профессионалы: Никакой дополнительный код.
Недостатки: потраченное впустую перемещение в случаях 1 и 2. Производительность пострадает значительно если SomeClass не имеет никакого конструктора перемещения.


Что Вы думаете? Это корректно? Действительно ли понесенное перемещение является обычно приемлемой потерей при сравнении на пользу сокращению кода?

49
задан 4 revs, 3 users 100% 15 March 2013 в 01:59
поделиться

1 ответ

Меня заинтересовал ваш вопрос, потому что я был новичком в этой теме и провел некоторое исследование. Разрешите представить результаты.

Во-первых, ваш вздох.

:: sighs :: C ++ 0x должен был позволить мне писать меньше кода, а не больше!

это также должно дать вам лучший контроль над кодом. И это так. Я бы придерживался дополнительного конструктора:

OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

Я лично предпочитаю многословие в сложных и важных ситуациях, потому что это держит меня и возможных читателей моего кода в курсе.

возьмем, например, приведение в стиле C (T *) pT и стандарт C ++ static_cast (pT) Гораздо более подробный - но большой шаг вперед.

Во-вторых, я немного подозрительно отнесся к вашему примеру 3, последнему тесту. Я подумал, что может быть задействован другой конструктор перемещения для создания переданного по значению параметра из rvalue.Итак, я создал небольшой проект в моем новом VS2010 и получил некоторые пояснения. Я отправлю сюда код и результаты.

источник:

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <utility>
#include <iostream>

class SomeClass{
    mutable int *pVal;
public:
    int Val() const { return *pVal; };
    SomeClass(int val){
        pVal = new int(val);
        std::cout << "SomeClass constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    SomeClass(const SomeClass& r){
        pVal = new int(r.Val());
        std::cout << "SomeClass copy constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }   
    SomeClass(const SomeClass&& r){
        pVal = r.pVal;
        r.pVal = 0;
        std::cout << "SomeClass move constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    ~SomeClass(){
        if(pVal)
            delete pVal;
        std::cout << "SomeClass destructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
};

class OtherClass{
    SomeClass sc;
public:
    OtherClass(int val):sc(val){
    }

Обратите внимание на этот раздел:

#if 1
    OtherClass(SomeClass r):sc(std::move(r)){
    }
#else
    OtherClass(const SomeClass& r):sc(r){
    }   
    OtherClass(const SomeClass&& r):sc(std::move(r)){
    }
#endif

...

    int Val(){ return sc.Val(); }
    ~OtherClass(){
    }
};

#define ECHO(expr)  std::cout << std::endl << "line " << __LINE__ << ":\t" #expr ":" << std::endl; expr

int _tmain(int argc, _TCHAR* argv[])
{
    volatile int __dummy = 0;
    ECHO(SomeClass o(10));

    ECHO(OtherClass oo1(o));            
    __dummy += oo1.Val();
    ECHO(OtherClass oo2(std::move(o))); 
    __dummy += oo2.Val();
    ECHO(OtherClass oo3(SomeClass(20)));  
    __dummy += oo3.Val();

    ECHO(std::cout << __dummy << std::endl);
    ECHO(return 0);
}

Как вы заметили, есть переключатель времени компиляции, который позволяет мне протестировать два подхода.

Результаты лучше всего просматривать в режиме сравнения текста, слева вы можете увидеть компиляцию #if 1 , что означает, что мы проверяем предлагаемый обходной путь, а справа - #if 0 , что означает, что мы проверяем "кошерный" способ, описанный в c ++ 0x!

Я ошибался, подозревая, что компилятор делает глупости; он сохранил дополнительный конструктор перемещения в третьем тестовом примере.

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

В любом случае, я не собираюсь останавливаться на достигнутом, что лучше написать еще один конструктор в классе-оболочке. Это всего лишь вопрос нескольких строк, поскольку вся утомительная работа уже проделана в SomeClass , который имеет , чтобы иметь конструктор перемещения.

8
ответ дан 7 November 2019 в 11:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: