Что такое std:: move (), и когда его следует использовать?




  1. что это?

  2. что он делает?

  3. , когда его следует использовать?

хорошие ссылки.
1207   6  

6 ответов:

http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

  1. в C++11, помимо конструкторов копирования, объекты могут иметь конструкторы перемещения.
    (И в дополнение к операторам присваивания копирования у них есть операторы присваивания перемещения.)
  2. конструктор перемещения используется вместо конструктора копирования, если объект имеет тип "rvalue-reference" (Type &&).
  3. std::move() - это приведение, которое создает rvalue-ссылку на объект, чтобы разрешить перемещение из него.

Это новый способ C++, чтобы избежать копий. Например, используя конструктор перемещения, a std::vector может просто скопировать свой внутренний указатель на данные в новый объект, оставив перемещенный объект в неправильном состоянии, избегая копирования всех данных. Это было бы c++-допустимо.

попробуйте погуглить для семантики перемещения, rvalue, идеальная пересылка.

вы можете использовать move, когда вам нужно "перенести" содержимое объекта в другое место, не делая копию (например, содержимое не дублируется, поэтому его можно использовать на некоторых не копируемых объектах, таких как unique_ptr). Кроме того, объект может принимать содержимое временного объекта без копирования (и сэкономить много времени) с помощью std::move.

эта ссылка действительно помогла мне :

http://thbecker.net/articles/rvalue_references/section_01.html

извините, если мой ответ приходит слишком поздно, но я также искал хорошую ссылку для std::move, и я нашел ссылки выше немного "строгие".

Это поставило акцент на ссылку r-value, в каком контексте вы должны их использовать, и я думаю, что это более подробно, поэтому я хотел поделиться этой ссылкой здесь.

1. -В чем дело?"

пока std::move() технически функция - я бы сказал это не действительно функция. Это своего рода конвертер между способами компилятор учитывает значение выражения.

2. "Что он делает?"

первое, что нужно отметить, что std::move()не все.

если вы когда-нибудь смотрели мультсериал отбеливатель - он делает эквивалент Куинси Seele Schneider ' s Рейши размягчения.

серьезно, однако, он преобразует выражение изименующее или чисто правосторонним значением (например, переменная, которую вы можете использовать в течение длительного времени, или временная, которую вы передаете на некоторое время, соответственно), чтобы быть xvalue. В тихую говорит компилятор:

можно грабить я,движение все, что я держу и использую его в другом месте (так как я все равно скоро буду уничтожен)".

другими словами, когда вы используете std::move(x), вы позволяете компилятору раскулачить x. Таким образом, если x есть, скажем, свой собственный буфер в памяти - после std::move()рый компилятор может иметь другой объект, а не его владельцем.

3. "Когда его следует использовать?"

другой способ задать этот вопрос: "Что бы я использовать/раскулачить в ресурсы объекта для?"ну, если вы пишете код приложения, вы, вероятно, не будете много возиться с временными объектами, созданными компилятором. Так что в основном это делается в таких местах, как конструкторы, операторных методов, библиотеки STL-алгоритма-функции и т. д. где объекты создаются и уничтожаются автоматически много. Конечно, это всего лишь эмпирическое правило.

типичное использование-это "перемещение" ресурсов из одного объекта в другой вместо копирования. @Гийом ссылки на на этой странице который имеет простой короткий пример: замена двух объектов с меньшим количеством копирования.

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

использование move позволяет менять местами ресурсы, а не копировать их вокруг:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

подумайте о том, что происходит, когда T, скажем,vector<int> размера n.в первой версии вы читаете и записываете 3*n элементов, во второй версии вы в основном читаете и записываете только 3 указателя на буферы векторов. Конечно, класс T должен знать, как это сделать перемещение; у вас должен быть оператор назначения перемещения и конструктор перемещения для класса T, чтобы это работало.

Q: Что такое std::move?

A:std::move() - это функция из стандартной библиотеки C++ для приведения к ссылке rvalue.

появилась реклама std::move(t) эквивалентно:

static_cast<T&&>(t);

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

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

реализация для std:: move () задается в N2027: "Краткая Введение в ссылки Rvalue" следующим образом:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

Как видите, std::move возвращает T&& независимо от того, если назвать со значением (T), тип ссылки (T&) или ссылка rvalue (T&&).

Q: что он делает?

A: как приведение, он ничего не делает во время выполнения. Важно только во время компиляции сообщить компилятору, что вы хотели бы продолжить рассмотрение ссылки как rvalue.

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

что это значит не do:

  • сделайте копию аргумента
  • вызовите конструктор копирования
  • изменить объект аргумента

Q: когда он должен быть использован?

A: Вы должны использовать std::move если вы хотите вызвать функции, которые поддерживают семантику перемещения с аргументом, который не является rvalue (временное выражение).

напрашивается следующий последующие вопросы для меня:

  • что такое семантика перемещения? Семантика перемещения в отличие от семантики копирования-это метод программирования, в котором члены объекта инициализируются путем "захвата" вместо копирования членов другого объекта. Такой "захват" имеет смысл только с указателями и дескрипторами ресурсов, которые могут быть дешево переданы путем копирования указателя или целочисленного дескриптора, а не базовых данных.

  • какие классы и объекты поддерживают семантику перемещения? Это зависит от вас как разработчика, чтобы реализовать семантику перемещения в ваших собственных классах, если они выиграют от передачи своих членов вместо их копирования. Как только вы реализуете семантику перемещения, вы получите прямую выгоду от работы многих программистов библиотеки, которые добавили поддержку для эффективной обработки классов с семантикой перемещения.

  • почему компилятор не может понять это самостоятельно? Компилятор не может просто вызвать еще одна перегрузка функции, если вы так не скажете. Вы должны помочь компилятору выбрать, следует ли вызывать обычную или перемещаемую версию функции.

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

std:: move сам по себе не очень много делает. Я думал, что он вызвал перемещенный конструктор для объекта, но на самом деле он просто выполняет приведение типа (приведение переменной lvalue к rvalue, чтобы указанную переменную можно было передать в качестве аргумента конструктору перемещения или оператору присваивания).

таким образом, std:: move просто используется в качестве предшественника использования семантики перемещения. Семантика перемещения по существу является эффективным способом работы с временными объектами.

Рассмотреть Объект A = B + C + D + E + F;

Это красивый код, но E + F создает временный объект. Затем D + temp создает еще один временный объект и так далее. В каждом нормальном операторе класса "+" происходят глубокие копии.

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

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

мы можем скорее использовать семантику перемещения для "грабежа" временные объекты и сделать что-то вроде

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }

это позволяет избежать ненужных глубоких копий. Со ссылкой на пример, единственная часть, где происходит глубокое копирование, теперь E + F. остальное использует семантику перемещения. Конструктор перемещения или оператор присваивания также должны быть реализованы, чтобы присвоить результат A.

What is it? и What does it do? было объяснено выше.

приведу пример when it should be used.

например, у нас есть класс с большим количеством ресурсов, как большой массив в нем.

class ResHeavy{ //  ResHeavy means heavy resource
    public:
        ResHeavy(int len=10):_upInt(new int[len]),_len(len){
            cout<<"default ctor"<<endl;
        }

        ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
            cout<<"copy ctor"<<endl;
        }

        ResHeavy& operator=(const ResHeavy& rhs){
            _upInt.reset(new int[rhs._len]);
            _len = rhs._len;
            cout<<"operator= ctor"<<endl;
        }

        ResHeavy(ResHeavy&& rhs){
            _upInt = std::move(rhs._upInt);
            _len = rhs._len;
            rhs._len = 0;
            cout<<"move ctor"<<endl;
        }

    // check array valid
    bool is_up_valid(){
        return _upInt != nullptr;
    }

    private:
        std::unique_ptr<int[]> _upInt; // heavy array resource
        int _len; // length of int array
};

тестовый код:

void test_std_move2(){
    ResHeavy rh; // only one int[]
    // operator rh

    // after some operator of rh, it becomes no-use
    // transform it to other object
    ResHeavy rh2 = std::move(rh); // rh becomes invalid

    // show rh, rh2 it valid
    if(rh.is_up_valid())
        cout<<"rh valid"<<endl;
    else
        cout<<"rh invalid"<<endl;

    if(rh2.is_up_valid())
        cout<<"rh2 valid"<<endl;
    else
        cout<<"rh2 invalid"<<endl;

    // new ResHeavy object, created by copy ctor
    ResHeavy rh3(rh2);  // two copy of int[]

    if(rh3.is_up_valid())
        cout<<"rh3 valid"<<endl;
    else
        cout<<"rh3 invalid"<<endl;
}

выход, как показано ниже:

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

мы это видим std::move С move constructor делает ресурс преобразования легко.

где еще находится std:: move полезно?

std:: move также может быть полезен при сортировке массива элементов. Многие алгоритмы сортировки (сортировка выбором и пузырьковая сортировка) работы, меняя пары элементов. В предыдущем случае нам пришлось прибегнуть к копировальной семантике, чтобы сделать обмен. Теперь мы можем использовать семантику перемещения, которая более эффективна.

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

привел:

https://www.learncpp.com/cpp-tutorial/15-4-stdmove/

Comments

    Ничего не найдено.