0

I have some type like this:

#pragma once

#include <stdio.h>
#include <string>

struct Color {
    std::string value;
};

struct Shirt {
    std::string brand;
    Color color;
};

class Outfit {
public:
    Outfit(Shirt shirt):
        shirt(shirt) {}

private:
    Shirt shirt;
};

I previously reviewed this Stackoverflow thread on this topic.

Let me explain my thinking, and I'd like for anyone here to tell me if I'm correct or incorrect or if there's something I didn't consider or misunderstood.

My current understanding is I should pass in the arguments as const reference. If I pass by value, then when I create an instance of Outfit, for example, Shirt will be be copied. If I understood correctly, this might be dangerous. The copy and the original Outfit will point to the same Shirt instance. And this shared ownership model is dangerous because we don't know if Shirt gets released.

Is that understanding correct? Or am I overcomplicating this?

Beebunny
  • 4,190
  • 4
  • 24
  • 37
  • Your understanding is incorrect. `shirt` is a _value_ member, which means that the default copy constructor the compiler generates will create a copy of `shirt` (and hence a copy of `brand` and `color`) when it needs to make a copy of an `Outfit` object. You might still want to use `const` reference to avoid making those copies, but you don't need to worry about multiple objects sharing members. If `shirt` was a `Shirt*` instead of a `Shirt`, you'd have to be more careful with Rule of 3/5/0 stuff. – Nathan Pierson May 07 '21 at 01:16
  • If you want to intent ownership, use a pointer or smart pointers. The above code is just a value. Or did you mean `Shirt` will be implemented as a shared memory model later with itself? – 김선달 May 07 '21 at 01:24
  • If you share objects through references, you need to worry about object lifetimes. If everything's a copy, it's a lot fewer headaches. – Mark Ransom May 07 '21 at 03:32
  • @NathanPierson Thanks for your post. This was very helpful. If you posted as an answer I would have accepted. Appreciate your time. – Beebunny May 11 '21 at 18:55

1 Answers1

1

The copy and the original Outfit will point to the same Shirt instance

No this is wrong. A copy has no relationship to the original except if it also contains pointers. In that case, the pointers will still point to whatever they referred to before the copy was made. However, even the pointers themselves are not the same. So doing anything that may affect the pointer such as incrementing (pointer++) will not affect the other pointer.

In either

Outfit(Shirt shirt): shirt(shirt) {}

or

Outfit(const Shirt& shirt): shirt(shirt) {}

A copy is made.

How it is done depends on which one you choose. I would argue that the second option is preferred because only the copy constructor is called to make a copy of the shirt parameter, but the first will make a copy and then the move constructor is used to "move" the copy into the shirt field.

smac89
  • 39,374
  • 15
  • 132
  • 179