18

I have googled these terms but I am still confused.

Some people said that memberwise copy is deep copy and the bitwise copy is shallow copy but someone said it is not.

Can anyone explain to me that which type of copy of the default copy constructor and the user-defined copy constructor use?

Martin Ba
  • 37,187
  • 33
  • 183
  • 337
Kelvinyu1117
  • 509
  • 1
  • 5
  • 14
  • 1
    A _deep copy_ might include copy construction, while _bitwise copy_ doesn't. – πάντα ῥεῖ Mar 12 '17 at 15:47
  • 9
    if this question was in fact "too broad" then you would expect to see a multitude of answers, none of which would manage to give it a satisfactory coverage. As we see, so far there have been only two answers, and they both do a pretty decent job at covering it. Please do not vote to close a question just because you are bored to write the lengthy enough text needed to cover it. There are others who do like writing, and will write. – Mike Nakis Mar 13 '17 at 08:07

3 Answers3

33

Member-wise Copy

Is when you visit each member and explicitly copy it, invoking its copy constructor. It is the proper way of copying things. If done right, it is tantamount to a deep-copy, because each member whose copy constructor you invoke will (or should) in turn perform member-wise copy of its own members, and so on. The opposite is bit-wise copy, which is a hack, see below.

Bit-wise Copy

Is a specific form of shallow copy. It is when you simply copy the bits of the source class to the target class, using memcpy() or something similar. Constructors are not invoked, so you tend to get a class which appears to be all right but things start breaking in horrible ways as soon as you start using it. This is the opposite of member-wise copy, and is a quick and dirty hack that can sometimes be used when we know that there are no constructors to be invoked and no internal structures to be duplicated. For a discussion of what may go wrong with this, see this Q&A: C++ bitwise vs memberwise copying?

Shallow Copy

Refers to copying just the immediate members of an object, without duplicating whatever structures are pointed by them. It is what you get when you do a bit-wise copy.

(Note that there is no such thing as "shadow copy". I mean, there is such a thing, in file systems, but that's probably not what you had in mind.)

Deep Copy

Refers to not only copying the immediate members of an object, but also duplicating whatever structures are pointed by them. It is what you normally get when you do member-wise copy.

To summarize:

There are two categories:

  • Shallow Copy
  • Deep Copy

Then, there are two widely used techniques:

  • Bit-wise Copy (a form of Shallow Copy)
  • Member-wise Copy (a form of Deep Copy, if done right.)

As for the hear-say about someone who said something and someone who said something else: bit-wise copy is definitely always shallow copy. Member-wise copy is usually deep copy, but you may of course foul it up, so you may be thinking that you are making a deep copy while in fact you are not. Proper member-wise copy relies on having proper copy constructors.

Finally:

The default copy constructor will do a bit-wise copy if the object is known to be trivially copyable, or a member-wise copy if not. However, the compiler does not always have enough information to perform a proper copy of each member. For example, a pointer is copied by making a copy of the pointer, not by making a copy of the pointed object. That's why you should generally not rely on the compiler providing you with a default copy constructor when your object is not trivially copyable.

A user-supplied constructor may do whatever type of copy the user likes. Hopefully, the user will choose wisely and do a member-wise copy.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • 2
    The C++11 template `std::is_trivially_copyable` is intended to determine when shallow copy is valid and specifically when `memcpy()` is OK. – Persixty Mar 12 '17 at 16:34
  • "For example, a pointer is copied by making a copy of the pointer, not by making a copy of the pointed object." I was looking for a reason behind the name bit-wise and this sentence somehow connects the dots for me, thanks! – gawkface Aug 17 '17 at 12:22
  • "Member-wise Copy ... usually tantamount to deep-copy" - I think this needs revisiting. A compiler generated copy-ctor does a memberwise copy, but this will not be a deep copy in the presence of raw pointers. – Martin Ba Jul 13 '22 at 09:43
  • @MartinBa under "Finally:" above, I wrote: "The default copy constructor will do a bit-wise copy if the object is known to be trivially copyable, or a member-wise copy if not. However, the compiler does not always have enough information to perform a proper copy of each member. For example, a pointer is copied by making a copy of the pointer, not by making a copy of the pointed object." Does this not cover your concern? – Mike Nakis Jul 13 '22 at 13:49
  • @MikeNakis - it is exactly this why I think writing "memberwise ... usually tantamount to deep-copy" is an oversimplification to start with. The Std calls out "memberwise" as a specific form of the generated copy ops, and I think it is not "usually" here nor there. It's just stupid/mechanic and what it does depends on the member types. – Martin Ba Jul 14 '22 at 10:43
  • @MartinBa Okay, you are right. I amended that part of the answer. I hope it is better now. – Mike Nakis Jul 14 '22 at 13:31
2

The short version:

  • a bitwise copy is a copy of a block of memory
  • a memberwise copy is a copy that requires intimate knowledge of the structure of data that's being copied

The simplest way to illustrate the difference is with a pointer member:

  • by performing a bitwise copy, you're only gonna copy the address of memory it points to.
  • by performing a memberwise copy, you would make a copy of the memory the pointer points to, and then initialize the copied member pointer with the address to that new memory area

Example:

struct A 
{
   int* m_a;

   A() 
   {
      m_a = new int[1];
   }

   ~A()
   {
     delete [] m_a;
   }
};

A obj;

printf("%p\n", obj.m_a);  // prints: 0x10001000 (for example)

Bitwise copy

A copiedObj = obj;        // the default copy constructor is employed
                          // it will perform a bitwise copy

printf("%p\n", copiedObj.m_a);  // prints: 0x10001000 - the same address

now both obj.m_a and copiedObj.m_a point to the same address in memory.

Notice, that with a class definition like that, if you would try to delete both objects, you would run into a memory access exception (the object to be deleted as the second one would try deallocating the memory that's already been deallocated).

Memberwise copy

struct A 
{
    A(const A& rhs)  // let's define a custom copy constructor
    {
        m_a = new int[1];
        memcpy(m_a, rhs.m_a, sizeof(int) * 1);
    }
}

A copiedObj = a;

printf("%p\n", copiedObj.m_a);  // prints: 0x9a001234 - a totally different address

The custom operation we performed in our custom copy constructor made a copy of the memory the pointer of the original object was pointing to.

Last but not least - memberwise copy is not limited to copy constructors. Think of it as an operation that operates on the memory area an object resides in.

Piotr Trochim
  • 693
  • 5
  • 15
  • The two are one and the same. I meant that by performing a bitwise copy, only the contents of the pointer is gonna be copied. A pointer is just a 4(or 8) byte long value that contains an address of memory. Only that value will be copied, not the memory the address points to. – Piotr Trochim Mar 13 '17 at 14:32
2

The 4 terms:

  • memberwise copy
  • bitwise copy
  • shallow copy
  • deep copy

do not exist on the same axis of meaning.

The Deep Copy is what most people, in most circumstances, would expect from a semantic object in programming when they say: "Computer, give me a copy".

Specifically, in the context of C++, it would mean that the copy of an existing object has also recursively copied all sub-objects, no matter how they are implemented. (Pointers, ints, other complex objects, ...)

The Shallow Copy is what you get when you do not take into account that some direct in-memory members of an object are in fact pointers (of some sort) and you only copy their "pointer value" instead of following the indirection and creating proper copies of the pointed-to objects as well.

Shallow Copy is what you get in C++ when the compiler does a naive memberwise copy (see below) and your object contains (raw) pointers. Shallow copy is also what you get in Java or C# if you do a naive copy of any object, because there, "everything" is a pointer/reference.

If you have a trivially copyable object, e.g. a struct containing only ints then a shallow copy is the same as a deep copy.

The Bitwise Copy is what you get in C++ when you do a memcpy() of an in-memory object. The result may be a Deep copy semantically, or (more likely) a Shallow Copy (if pointers involved) or it may result in just a bunch of bits in memory that are no longer of the form of a valid object of the type being copied from.

Finally, the Memberwise Copy is, within C++, a specific term called out by the C++ Std for what a compiler generated copy C'tor will do when being invoked. Specifically:

The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members. (...)

in [class.copy.ctor] and it goes on to describe what that means:

Each base or non-static data member is copied/moved in the manner appropriate to its type: (...)

(!!) A Memberwise Copy can be semantically equivalent to all of the 3 types above, depending on the object.

(I note at this point that the C++ Std always uses "memberwise", never "member-wise", but my auto correction prefers "member-wise" or "member wise" -- this may help when googling.)

As far as I'm concerned, if you have a user-defined copy ctor, you never (should) see 1:1 memberwise copy, because if you do 1:1 memberwise copy you do not need to implement the ctor, the compiler will generate it for you anyway.

To make a few comparisons:

  • If you have a structof ints, then a memberwise copy results in the same thing as a bitwise copy, and it is a shallow copy as well as a deep copy (well, there ain't no depth t speak of).
  • If you have a struct of int* pointers, than a memberwise copy is the same as a bitwise copy, and it is also a shallow copy, but it is no longer a deep copy, because the copy will point to the same integers as the original.
  • If you have a struct containing any non-trivial object (e.g. a std::string), then a bitwise copy is no longer valid, and whether a memberwise copy is shallow or deep depends on the implementation of the sub-objects: If the subobjects all implement deep-copy on copy construction, the the copy is deep. If you have any subobject member that only does shallow copies, then the memberwise copy will also be (partially) shallow.
Martin Ba
  • 37,187
  • 33
  • 183
  • 337