does queue create a copy?

Viewed 1859

If I push an existing object into a queue:

struct Node {int x; int y;};
std::vector<Node> vec;
vec.push_back(Node(1, 3));

std::queue<Node> q;
q.push(vec[0]);

At the last line, does q store the address (pointer or reference, whatever except the object itself) of vec[0], or does it copy the whole Node object into q?

3 Answers

It will get copied as you assign an rvalue reference. It will get moved if you assign an lvalue reference. (temporary object).

To check, use copy constructor / operator and move constructor / operator overloading:

#include <iostream>
#include <vector>
#include <queue>

struct Node {
    int x;
    int y;

    Node(int x, int y) : x(x), y(y)
    {
        std::cout << "constructor" << std::endl;
    }

    Node(Node const & original) : x(original.x), y(original.y)
    {
        std::cout << "copy constructor" << std::endl;
    }

    Node(Node const && original) : x(original.x), y(original.y)
    {
        std::cout << "move constructor" << std::endl;
    }

    Node & operator=(Node const & original) {
        std::cout << "assignment operator" << std::endl;
        if(this != &original) {
            x = original.x;
            y = original.y;
        }
        return *this;
    }

    Node & operator=(Node const && original) {
        std::cout << "move operator" << std::endl;
        if(this != &original) {
            x = original.x;
            y = original.y;
        }
        return *this;
    }
};


int main() {

    std::vector<Node> v;

    Node n(1,3);        // constructor
    Node m(3, 4);       // constructor

    m = n;              // assignment operator
    n = Node(2, 3);     // constructor + move operator

    v.push_back({1,2});     // constructor + move constructor
    v.push_back(n);         // copy constructor

    std::queue<Node> q;
    q.push(v[0]);           // copy constructor

    return 0;
}

It does create a copy. In fact, you can always find out where a copy or move occurs by overwriting the copy or move constructors:

class Node 
{
public:
    Node(int x, int y) { std::cout << "Create node" << std::endl; }
    Node(const Node&) { std::cout << "Copy node" << std::endl; }
    Node(Node&&) { std::cout << "Move node" << std::endl; }
    virtual ~Node() = default;
};

For your program this prints

Create node
Move node
Copy node

Since

std::vector<Node> vec;
vec.push_back(Node(1, 3));  // Creates a temporary node and moves it into the vector.

std::queue<Node> q;
q.push(vec[0]);             // Copys the node.

As per the doc the signatures of push function in queue are:
std::queue::push(const value_type& val)
std::queue::push(value_type&& val)

So it is basically gets copied to the queue, which can be verified by:

#include <iostream>
#include <queue>

int main() {
    int iarray[3] = { 1,2,3 };
    std::queue<int> q;
    q.push(iarray[2]);
    std::cout << q.front();
    iarray[2] = 4;
    std::cout << q.front();
    return 0;
}

To clarify,

This is what happens:

the line q.push(iarray[2]); calls void push (const value_type& val)
from the queue class.

The definition of void push (const value_type& val) is:

void push(const value_type& _Val) {
    c.push_back(_Val);
}

Where c is a protected instance of the _Container class
The line c.push_back(_Val) actually calls the copy constructor of the _Val object

Related