Search code examples
c++stdliststdmove

getting invalid ouput after std::move of an element from std::list


I'm trying to understand about std::move. In my code I'm moving an element from std::list<struct Data> where struct Data internally contains two std::string fields, but I'm not getting expected output. This is my code:

#include <iostream>
#include <string>
#include <list>

struct Data {
    std::string topic {};
    std::string msg {};

    Data(const std::string& topic, const std::string& msg) {
        this->topic = topic;
        this->msg = msg;
    }
};

int main() {
    std::list<Data> data_list;
    data_list.push_back(Data("A", std::string(1000, 'a')));
    data_list.push_back(Data("B", std::string(1000, 'b')));
    data_list.push_back(Data("C", std::string(1000, 'c')));
    data_list.push_back(Data("D", std::string(1000, 'd')));
    data_list.push_back(Data("E", std::string(1000, 'e')));
    
    while (!data_list.empty()) {
        std::cout << (void*)&data_list.front() << "\n";
        Data&& d1 = std::move(data_list.front());
        data_list.pop_front();
        std::cout << d1.topic << ", " << d1.msg << "\n";
        std::cout << (void*)&d1 << "\n\n";
    }
    std::cout << std::endl;
}

Solution

  • The issue here is you are not actually moving anything. When you call std::move, nothing is actually moved. What it does do is converts the lvalue that you have into an rvalue, so that it can then be move constructed or move assigned from. That's not what you are doing here though. You use

    Data&& d1 = std::move(data_list.front());
    

    which has d1 as an rvalue reference, meaning no move again, it's just a reference to the object in the list. When you pop that element, your reference is now refering to an object that no longer exits, and using it has undefined behavior leading to the output that you are seeing. If you want to move the element, you need

    Data d1 = std::move(data_list.front());
    

    and now d1 will use Data's implicit move constructor to move the list element into d1.