c++ – How to avoid unnecessary copy while pushing/popping data into/from queue

In my learning course, I’ve implemented a message queue to which data gets pushed by some thread and later gets processed by some other thread. My implementation is not that effective as it involves creating minimum three copies of the same data which is not acceptable. So is there any way to avoid these unnecessary copies? This is my sample working code:

#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <condition_variable>

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

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

std::mutex net_mutex {};
std::mutex pro_mutex {};

std::condition_variable net_cond_var {};
std::condition_variable pro_cond_var {};

std::list<Data> net_list;
std::list<Data> pro_list;

void pro_thread() {
    while (true) {
        std::unique_lock<std::mutex> ul(pro_mutex);

        pro_cond_var.wait(ul, () () { return not pro_list.empty(); });
        Data data = pro_list.front(); // third copy
        pro_list.pop_front();

        ul.unlock();

        // do processing
    }
}

void relay_thread() {
    while (true) {
        // relays received network data to different processing threads based upon topic

        std::unique_lock<std::mutex> ul(net_mutex);

        net_cond_var.wait(ul, () () { return not net_list.empty(); });
        Data data = net_list.front(); // second copy 
        pro_list.pop_front();

        ul.unlock();

        if (data.topic == "A") { // push data into pro_list queue
            pro_mutex.lock();

            pro_list.emplace_back(data);
            pro_cond_var.notify_one();

            pro_mutex.unlock();
        }
    }
}

void net_thread() {
    while (true) {
        // receives data from socket and pushes into net_list queue

        Data data("A", "Hello, world!");
        net_mutex.lock();

        net_list.emplace_back(data); // first copy
        net_cond_var.notify_one();

        net_mutex.unlock();
    }
}

int main() {
    std::thread net(net_thread);
    std::thread relay(relay_thread);
    std::thread pro(pro_thread);

    net.join();
    relay.join();
    pro.join();
}