2016-05-10 3 views
1

Может кто-нибудь объяснить, почему исходный объект, который передается новому объекту через std :: move, по-прежнему действует после?std :: move used, move constructor, но объект все еще действителен

#include <iostream> 

class Class 
{ 

public: 
    explicit Class(const double& tt) : m_type(tt) 
    { 
     std::cout << "defaultish" << std::endl; 
    }; 

    explicit Class(const Class& val) : 
     m_type(val.m_type) 
    { 
     std::cout << "copy" << std::endl; 
    }; 

    explicit Class(Class&& val) : 
     m_type(val.m_type) 
    { 
     m_type = val.m_type; 
     std::cout << "move: " << m_type << std::endl; 
    }; 

    void print() 
    { 
     std::cout << "print: " << m_type << std::endl; 
    } 

    void set(const double& tt) 
    { 
     m_type = tt; 
    } 

private: 

    double m_type;  
}; 

int main() 
{ 
    Class cc(3.2); 

    Class c2(std::move(cc)); 

    c2.print(); 

    cc.set(4.0); 
    cc.print(); 


    return 0; 
} 

Он выводит следующее:

defaultish 
move: 3.2 
print: 3.2 
print: 4 

Я бы ожидать, что вызовы cc.set() и cc.print() на провал ...

UPDATE Спасибо к ответам ниже, мы определили, что 1) я ничего не двигал в конструкторе перемещения, а 2) std::move() на int или double ничего не делает, потому что более дорогое перемещение этих типов, чем просто копирование. Новый код ниже обновляет переменную частного члена класса, которая будет иметь тип std :: string вместо double, и правильно вызывает std :: move при установке этой переменной частного члена в конструкторе перемещения класса, в результате получается вывод, который показывает, как ЗППП :: переместить результаты в действительного, но неустановленное состоянии

#include <iostream> 
#include <string> 

class Class 
{ 

public: 
    explicit Class(const std::string& tt) : m_type(tt) 
    { 
     std::cout << "defaultish" << std::endl; 
    }; 

    explicit Class(const Class& val) : 
     m_type(val.m_type) 
    { 
     std::cout << "copy" << std::endl; 
    }; 

    explicit Class(Class&& val) : m_type(std::move(val.m_type)) 
    { 
     std::cout << "move: " << m_type << std::endl; 
    }; 

    void print() 
    { 
     std::cout << "print: " << m_type << std::endl; 
    } 

    void set(const std::string val) 
    { 
     m_type = val; 
    } 

private: 

    std::string m_type;  
}; 

int main() 
{ 
    Class cc("3.2"); 

    Class c2(std::move(cc)); 
    c2.print(); 

    cc.print(); 
    cc.set("4.0"); 
    cc.print(); 

    return 0; 
} 

И, наконец, выход:

defaultish 
move: 3.2 
print: 3.2 
print: 
print: 4.0 

ответ

10

Поскольку стандарт так говорит.

Переведено из объектов действует, но неуточненное состояние. Это означает, что вы все еще можете их использовать, но вы не можете быть уверены в том, в каком состоянии они будут находиться. Они могут выглядеть так же, как и перед движением, в зависимости от того, что является самым эффективным способом «переместить» данные из них , Например, «перемещение» с int не имеет смысла (вам нужно было бы сделать extra работать, чтобы сбросить исходное значение!), Поэтому «перемещение» с int на самом деле будет только когда-либо копией. То же самое относится к double.

Хотя в этом случае это больше связано с тем фактом, что вы ничего не двигали.

+3

Как правило, вы можете вызывать функции-члены на перемещенном объекте, который не имеет предварительных условий (включая назначение и уничтожение). –

+0

Можете ли вы объяснить утверждение: «На самом деле вы ничего не двигали? Это потому, что я забыл удалить список инициализаторов? – Wond3rBoi

+1

@ Wond3rBoi Вы использовали' m_type (val.m_type) 'вместо' m_type (std :: move (val ,m_type)) 'в вашем движении ctor. Однако это не делает ничего (для 'double'), как объяснено в этом ответе. – user2296177

3

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

Все разговоры в комментариях и ответов по поводу состояния объекта, который был перемещен из примерно требований по стандартным типам библиотеки, которые будут оставлены в «действительном, но неустановленном государстве» (17.6.5.15, [lib.types.movedfrom]). То, что вы делаете с вашими типами, не зависит от этого.

EDIT: вздох. Вы отредактировали код и изменили вопрос. Теперь, когда ваш класс содержит std::string вместо float, все будет по-другому, а объект std::string в cc действительно находится в «действительном, но неуказанном состоянии».

Смежные вопросы