2

I'm studying std::move semantics and I would like this to be clarified to me:

Say I have:

// Message.h
class Message
{
private:
    std::array<uint8_t, BUFFER_SIZE> buffer;
    std::queue<Packet> packets;

public:
    Message(Packet p)
    {
        packets.push(std::move(p));
    }
}

Now I have:

Packet p;

p << data; // put data into the packet

Message m(p) // wrap the packet in a message.

So this code generates unnecessary copies for my use case, because I will never use p ever again. So I'd like to use the std::move semantics to avoid every copy possible.

What I don't understand is the following:

If I do:

Packet p;

Message m(std::move(p));

While the constructor of Message is still

Message(Packet p) // p is passed by value

p is passed by value, so is it still copied?

Also both of these work:

Packet a;
Packet b;

Message mess1(std::move(a));  // no errors
Message mess2(b);             // no errors

But I fail to see the difference. The first one prevents the copy (even with that constructor) and the seconds allows the copy? Or not?

While If I modify the constructor so that:

Message(Packet&& c)

Am I right to assume that in this case no copies will ever be made and I'm basically forcing the programmer to use std::move(a) otherwise the program won't compile?

I tried to do multiple tests with objects and try to understand the difference but I couldn't.

7
  • Note with && and std::move no move construction actually gets performed, and no unnecessary temporary object is created either Commented Jul 12 at 23:29
  • The way Message is defined, it would need to copy the data stored in Packet anyway. So take const Packet& - that at least would avoid copying Packet itself. Your design wouldn't benefit from move semantics. Commented Jul 12 at 23:31
  • @PatrickRoberts I've done some logging in the move constructor and you're right! How so tho? How does the packet arrive to the constructor? As it was a simple const Packet& reference? Commented Jul 12 at 23:39
  • @IgorTandetnik You're absolutely right! I've changed the example a little bit to prevent that. Commented Jul 12 at 23:47
  • A Packet const& is a reference. A Packet& is a reference. A Packet&& is a reference. They're all references. Each variant has some slight contractual differences, because they're for different use cases. A reference is like an alias that refers to the same object, but doesn't manage the object's lifetime (with the exception of lifetime extension, which does manage the object's lifetime). Pass by value makes a copy. Pass by reference does not make a copy. Commented Jul 13 at 0:18

1 Answer 1

3

While the constructor of Message is still
Message(Packet p) // p is passed by value
p is passed by value, so is it still copied?

If you pass a Packet lvalue to that constructor like you've shown in your question, it'll be copied.

While If I modify the constructor so that:
Message(Packet&& c)
Am I right to assume that in this case no copies will ever be made and I'm basically forcing the programmer to use std::move(a) otherwise the program won't compile?

That constructor will only accept rvalues, yes, but if that prevents copies depends entirely on how Packet is implemented. If it has a move constructor, that will be used. If that constructor does something that prevents a deep copy depends on how it's implemented.


If you had a Message that supported perfect forwarding

class Message {
private:
    std::queue<Packet> packets;

public:
    template <class... Args>
        requires std::constructible_from<Packet, Args...>
    explicit Message(Args&&... args) {
        packets.emplace(std::forward<Args>(args)...);
    }

    /* you probably want this too:
    template <class... Args>
        requires std::constructible_from<Packet, Args...>
    decltype(auto) emplace(Args&&... args) {
        return packets.emplace(std::forward<Args>(args)...);
    }
    */
};

and Packet had a constructor taking data as-is, you could simply do

Message m(data);

and there would only be one Packet instance - the one created inside packets.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.