Shallow copy or Deep copy?
Asked Answered
A

6

40

I am a bit new to these two methods of copying one object into the other. I am confused and unable to spot out the major difference between deep copy and shallow copy.. I had gone through a lots of theory regarding this, but I need explanation with proper examples.. I have program in which I copy one object into another. -->

   class A
    {
        public int a = 0;
        public void display()
        {
            Console.WriteLine("The value of a is " + a);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = new A();
            ob2 = ob1;
            ob2.display();
            Console.Read();
        }
    }

Is this a shallow copy or a deep copy ? Can anyone please provide the answer with reason. If it is a deep copy, then please provide the code for shallow copy for this program doing the same job of object copying, and the other way around..

If the above is a shallow copy, then even this should be a shallow copy-->

            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = ob1;
            ob2.a = 444;
            ob1.display();
Apocarp answered 5/8, 2013 at 19:45 Comment(8)
That's a shallow copy.Discussant
Wikipedia page about object copying: en.wikipedia.org/wiki/Object_copyShorn
@VaughanHilts - I would not call it "shallow copy" as code above does not perform any copy of an obj1 at all...Age
need for copies is code smell, maybe you should use immutable types in that caseValero
There are many questions/articles about deep/shallow copy/clone. It is very hard to see from you current sample what part of the copying you don't understand. Please update your question with reasonable Clone code instead of "searched a lot" text.Age
From the tag: "shallow copy contains a link(address in memory) to the original variable. Changes on shallow copies are reflected on origin object. "Discussant
The object created via A ob2 = new A(); is being discarded almost immediately. The next line makes ob2 a reference to the same object as ob1, and new A() is lost until it's garbage-collected.Naturalize
possible duplicate of What is the difference between a deep copy and a shallow copy?Raglan
D
61

From the link here

Shallow copies duplicate as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.

Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

Your example is creating a shallow copy.

A ob1 = new A();
ob1.a = 10;
A ob2 = new A();
ob2 = ob1;

ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 5.

Deep copy will be -

 A ob1 = new A();
 ob1.a = 10;
 A ob2 = new A();
 ob2.a = ob1.a;

 ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 10.
Dashiell answered 5/8, 2013 at 19:48 Comment(7)
I couldn't get you. 'coz you have not assigned ob1 to ob2, instead you did it for the variable a..Apocarp
By assigning ob2 to ob1 you are referring to same instance i.e. on any update in field of ob1 will be reflected in ob2 field.Dashiell
Updated my answer with reasoning.Dashiell
But, ob1 and ob2 have their own memory allocations that are different, as i have concretely instantiated both of them.. How can ob2 be dependent and pointing to ob1's memory allocation, instead ob2 should copy of the data from ob1's memory address, and not point to it..Apocarp
You have mistaken memory allocation concept. When you create two instances seperate memory allocation is done pointing to there own references. But once you equate them, they start pointing to same reference. Refer to this for detailed explanation - #7477573Dashiell
@RohitVats The first code snippet does not even seem to be a shallow copy to me. ob2 = ob1; just equates the references (as you put in a comment), no copying happens at all.Tongue
IMHO this is not a shallow copy as @Tongue suggests. Rather Look at https://mcmap.net/q/396043/-shallow-copy-or-deep-copy or https://mcmap.net/q/396043/-shallow-copy-or-deep-copyDropforge
C
18

In my opinion, it is not a strict shallow copy or deep copy. If I have to define it, I would say shallow copy.

ob2 = ob1; This code creates two object references that both refer to the same object. Therefore, any changes to the object made through ob1 will be reflected in subsequent uses of ob2.

Example from MSDN would be better to explain the differences for shallow copy, deep copy and just simply class copy.

 using System;

    public class IdInfo
    {
        public int IdNumber;

        public IdInfo(int IdNumber)
        {
            this.IdNumber = IdNumber;
        }
    }

    public class Person
    {
        public int Age;
        public string Name;
        public IdInfo IdInfo;

        public Person ShallowCopy()
        {
            return (Person)this.MemberwiseClone();
        }

        public Person DeepCopy()
        {
            Person other = (Person)this.MemberwiseClone();
            other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
            other.Name = String.Copy(this.Name);
            return other;
        }
    }

    public class Example
    {
        public static void Main()
        {
            // Create an instance of Person and assign values to its fields.
            Person p1 = new Person();
            p1.Age = 42;
            p1.Name = "Sam";
            p1.IdInfo = new IdInfo(6565);

            // Perform a shallow copy of p1 and assign it to p2.
            Person p2 = (Person)p1.ShallowCopy();

            // Display values of p1, p2
            Console.WriteLine("Original values of p1 and p2:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values:");
            DisplayValues(p2);

            // Change the value of p1 properties and display the values of p1 and p2.
            p1.Age = 32;
            p1.Name = "Frank";
            p1.IdInfo.IdNumber = 7878;
            Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values:");
            DisplayValues(p2);

            // Make a deep copy of p1 and assign it to p3.
            Person p3 = p1.DeepCopy();
            // Change the members of the p1 class to new values to show the deep copy.
            p1.Name = "George";
            p1.Age = 39;
            p1.IdInfo.IdNumber = 8641;
            Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p3 instance values:");
            DisplayValues(p3);

            // Make an equal of p1 and assign it to p4.
            Person p4 = new Person();
            p4 = p1;
            // Change the members of the p1 class to new values to show the equal copy.
            p1.Name = "Will";
            p1.Age = 30;
            p1.IdInfo.IdNumber = 8484;
            Console.WriteLine("\nValues of p1 and p4 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p4 instance values:");
            DisplayValues(p4);
        }

        public static void DisplayValues(Person p)
        {
            Console.WriteLine("      Name: {0:s}, Age: {1:d}", p.Name, p.Age);
            Console.WriteLine("      Value: {0:d}", p.IdInfo.IdNumber);
        }
    }

Here are the results:

Original values of p1 and p2:    p1 instance values:
      Name: Sam, Age: 42
      Value: 6565    p2 instance values:
      Name: Sam, Age: 42
      Value: 6565

Values of p1 and p2 after changes to p1:    p1 instance values:
      Name: Frank, Age: 32
      Value: 7878    p2 instance values:
      Name: Sam, Age: 42
      Value: 7878

Values of p1 and p3 after changes to p1:    p1 instance values:
      Name: George, Age: 39
      Value: 8641    p3 instance values:
      Name: Frank, Age: 32
      Value: 7878

Values of p1 and p4 after changes to p1:    p1 instance values:
      Name: Will, Age: 30
      Value: 8484    p4 instance values:
      Name: Will, Age: 30
      Value: 8484
Correlate answered 4/12, 2014 at 16:3 Comment(1)
String.Copy(this.Name) is not needed at all. In C# (as also in Java) Strings are immutable and so original and deep copied could share strings.Bloemfontein
B
5

This is neither a shallow nor a deep copy, this is a reference copy.let me explain: there are 2 types of variables : value types and reference types.

a value type is a (named) location in computer memory that hold the actual value of the variable. for example: int is a value type, so when you write this line of code:

int MyInt = 5;

when this line of code get executed the runtime will find a location in the RAM and write the value 5 in it. so if you search that location you will find an actual value of 5.

a reference type -in contrast- is a (named) location in memory that does not actually hold the value of the variable but hold the location of memory where that value exists. as an example suppose you wrote the following code:

MyClass myObject = new MyClass();

what happens is that the virtual machine (runtime): 1- look and find an available location in memory , create an instance of the MyClass class. lets say that the location of that object happened to be at byte # AA3D2 in RAM.

2- find a location in memory and create a reference of type MyClass (a reference is an "arrow" that point to a location in memory),name it "myObject" and store the value AA3D2 in it.

now if you look at the "myObject" variable you will find not the class instance but you will find AA3D2 which represent the location of memory that hold that class instance.

now lets examine the code given my the OP:

A ob1 = new A();

this will make a variable called ob1 ,create instance of the A class and store the location of that class in ob1

ob1.a = 10;
ob1.display();

this will change the variable a which is inside the A class. it then invoke the display() method

A ob2 = new A();

here it create a variable called ob2 ,create an instance of the class A and assign its location to ob2.

by now you have in memory 2 class instances of A and 2 variables each pointing to one of them. now here is the interesting part : ob2 = ob1;

the variable ob2 is assigned the value of the variable ob1. because ob1 contain the memory location of the first instance of A ,now both ob1 and ob2 point to the same location in memory. doing anything using one of them is exactly doing the same thin with the other.

ob2 = ob1 means you are copying the reference.

Ban answered 7/10, 2016 at 12:40 Comment(0)
D
2

It's a shallow copy because if you modify the variable of ob2 - and then try and print ob1 - they will be the same. This is because things in C# that are classes create links between themselves. If you want to do a deep copy, you should implement a copy method and copy the fields by hand. Something like:

  class A
    {
        public int a = 0;
        public void display()
        {
            Console.WriteLine("The value of a is " + a);
        }

       public A Copy()
    {
        A a = new A();
        a.a = = this.a;
        return a;
    }



    }
Discussant answered 5/8, 2013 at 19:48 Comment(0)
P
2

I endorse the answer from @docesam and part of the answer from @Will Yu.

This is neither a shallow nor a deep copy, this is a reference copy. -- docesam


ob2 = ob1; This code creates two object references that both refer to the same object. Therefore, any changes to the object made through ob1 will be reflected in subsequent uses of ob2. --Will Yu


According to MSDN (see Remarks):

A shallow copy of an Array copies only the elements of the Array, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new Array point to the same objects that the references in the original Array point to.

Here we have two things to note:

  1. A shallow copy copies elements.
  2. A shallow copy retains the original references of the elements.

Next, let me explain these two separately.


To begin with, we create a Person class with a Name property:

class Person
{
    public string Name {get; set;}
}

Then in the Main() method, we create a Person array.

// Create 2 Persons.
var person1 = new Person(){ Name = "Jack" };
var person2 = new Person(){ Name = "Amy" };

// Create a Person array.
var arrPerson = new Person[] { person1, person2 };

1. A shallow copy copies elements.

If we replace the first element in the shallow copy, the original array should not be affected:

// Create a shallow copy.
var arrPersonClone = (Person[]) arrPerson.Clone();

// Replace an element in the shallow copy.
arrPersonClone[0] = new Person(){Name = "Peter"};

// Display the contents of all arrays.
Console.WriteLine( "After replacing the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

Results:

The Original Array: Jack, Amy
The Shallow Copy: Peter, Amy

2. A shallow copy retains the original references of the elements.

If we change the properties of an element in the shallow copy, the original array will be affected, since the object which this element makes reference to is not copied.

// Create a new shallow copy.
arrPersonClone = (Person[]) arrPerson.Clone();

// Change the name of the first person in the shallow copy.
arrPersonClone[0].Name = "Peter";

// Display the contents of all arrays.
Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

Results:

The Original Array: Peter, Amy
The Shallow Copy: Peter, Amy

So how does a simple equal sign, =, behave?

It makes a reference copy. Any change to the elements or the referred objects will be reflected in both the original array and the "copied" array.

// Create a reference copy.
var arrPersonR = arrPerson;

// Change the name of the first person.
arrPersonR[0].Name = "NameChanged";
// Replace the second person.
arrPersonR[1] = new Person(){ Name = "PersonChanged" };

// Display the contents of all arrays.
Console.WriteLine( "After changing the reference copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );

Results:

The Original Array: NameChanged, PersonChanged
The Reference Copy: NameChanged, PersonChanged

In conclusion, ob2 = ob1 is not a shallow copy but a reference copy.

Full code to play with:

void Main()
{
    // Create 2 Persons.
    var person1 = new Person(){ Name = "Jack" };
    var person2 = new Person(){ Name = "Amy" };

    // Create a Person array.
    var arrPerson = new Person[] { person1, person2 };

    // ----------- 1. A shallow copy copies elements. -----------

    // Create a shallow copy.
    var arrPersonClone = (Person[]) arrPerson.Clone();

    // Replace an element in the shallow copy.
    arrPersonClone[0] = new Person(){Name = "Peter"};

    // Display the contents of all arrays.
    Console.WriteLine( "After replacing the first element in the Shallow Copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

    Console.WriteLine( "\n" );

    // ----------- 2. A shallow copy retains the original references of the elements. -----------

    // Create a new shallow copy.
    arrPersonClone = (Person[]) arrPerson.Clone();

    // Change the name of the first person in the shallow copy.
    arrPersonClone[0].Name = "Peter";

    // Display the contents of all arrays.
    Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

    Console.WriteLine( "\n" );  

    // ----------- 2. The equal sign. -----------

    // Create a reference copy.
    var arrPersonR = arrPerson;

    // Change the name of the first person.
    arrPersonR[0].Name = "NameChanged";
    // Replace the second person.
    arrPersonR[1] = new Person(){ Name = "PersonChanged" };

    // Display the contents of all arrays.
    Console.WriteLine( "After changing the reference copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );
}

class Person
{
    public string Name {get; set;}
}
Pulchritudinous answered 9/5, 2017 at 0:29 Comment(0)
C
0

Write a couple more lines of code to change the property of the first object after you assign it to the second object. Then call the display method on both objects and see what the results are. This will reveal to you that it is in fact a shallow copy.

Creativity answered 5/8, 2013 at 19:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.