ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 얕은 복사 (Shallow Copy) 와 깊은 복사 (Deep Copy)
    C# 2023. 3. 7. 18:14

    C#에서 객체를 복사하는 방법에는 복사와 깊은 복사 두 가지가 있습니다. 얕은 복사는 객체의 참조를 복사하여 같은 객체를 참조하는 경우가 있어 원본 객체와 복사본의 값이 공유될 수 있습니다. 반면, 깊은 복사는 객체의 모든 내용을 복사하여 원본 객체와는 독립적인 새로운 객체를 만듭니다.


    얕은 복사 (Shallow Copy)

    얕은 복사(Shallow Copy)객체의 참조만 복사하여 같은 객체를 참조하게 합니다. 따라서 원본 객체나 복사본 중 하나를 수정하면 다른 객체도 영향을 받을 수 있습니다.

     

    아래는 얕은 복사를 수행하는 예시 코드입니다.

    class MyClass {
        public int[] arr;
        public MyClass(int[] arr) {
            this.arr = arr;
        }
    }
    
    MyClass obj1 = new MyClass(new int[] { 1, 2, 3 });
    MyClass obj2 = obj1;  // 얕은 복사
    
    obj2.arr[0] = 4;
    Console.WriteLine(obj1.arr[0]);  // 출력: 4

     

    위 코드에서 obj1 객체와 obj2 객체는 같은 메모리를 참조하게 됩니다. 따라서 obj2.arr[0] = 4; 코드로 obj2arr 배열을 수정하면 obj1arr 배열도 같이 수정되어 Console.WriteLine(obj1.arr[0]); 코드에서 4가 출력됩니다.

     

       obj1       obj2
    +--------+  +--------+
    |  arr   |  |  arr   |
    |--------|  |--------|
    |   -->--+--+--<--   |
    |   [1]  |  |   [1]  |
    |   [2]  |  |   [2]  |
    |   [3]  |  |   [3]  |
    +--------+  +--------+

    위의 ASCII 아트는 obj1 객체와 obj2 객체를 얕은 복사할 때의 메모리 상태를 나타냅니다. obj1 객체는 { 1, 2, 3 } 배열을 참조하고 있습니다. obj2 객체를 obj1 객체로 얕은 복사하면, obj2 객체는 obj1 객체와 같은 { 1, 2, 3 } 배열을 참조합니다. 이 때, obj2.arr[0] = 4; 코드로 obj2 객체의 arr 배열을 수정하면, obj1 객체도 같은 배열을 참조하고 있기 때문에 obj1.arr[0] 값도 4로 변경됩니다.

     


    깊은 복사 (Deep Copy)

    깊은 복사(Deep Copy)객체의 내용을 모두 복사하여 원본 객체와는 독립적인 새로운 객체를 만듭니다. 따라서 한 객체의 수정이 다른 객체에 영향을 주지 않습니다.

     

    아래는 깊은 복사를 수행하는 예시 코드입니다.

    class MyClass {
        public int[] arr;
        public MyClass(int[] arr) {
            this.arr = (int[]) arr.Clone();  // 배열 복사
        }
    }
    
    MyClass obj1 = new MyClass(new int[] { 1, 2, 3 });
    MyClass obj2 = new MyClass(obj1.arr);  // 깊은 복사
    
    obj2.arr[0] = 4;
    Console.WriteLine(obj1.arr[0]);  // 출력: 1

    위 코드에서 obj1 객체와 obj2 객체는 서로 독립적인 객체입니다. 따라서 obj2.arr[0] = 4; 코드로 obj2arr 배열을 수정해도 obj1arr 배열은 영향을 받지 않습니다. 따라서 `Console.WriteLine(obj1.arr[0]);` 코드에서 1이 출력됩니다.

     

    C#에서 객체를 깊은 복사하는 방법 중 하나는 ICloneable 인터페이스를 구현하는 것입니다. ICloneable 인터페이스는 Clone 메서드를 정의하고 있으며, 메서드를 구현하여 객체를 복사할 수 있습니다. 다음은 ICloneable 인터페이스를 사용하여 MyClass 클래스를 깊은 복사하는 예시 코드입니다.

    class MyClass : ICloneable {
        public int[] arr;
        public MyClass(int[] arr) {
            this.arr = arr;
        }
    
        public object Clone() {
            int[] newArr = (int[]) arr.Clone();  // 배열 복사
            return new MyClass(newArr);
        }
    }
    
    MyClass obj1 = new MyClass(new int[] { 1, 2, 3 });
    MyClass obj2 = (MyClass) obj1.Clone();  // 깊은 복사
    
    obj2.arr[0] = 4;
    Console.WriteLine(obj1.arr[0]);  // 출력: 1

     

    위 코드에서 MyClass 클래스는 ICloneable 인터페이스를 구현하도록 변경되었습니다. Clone 메서드에서는 arr 배열을 복사하여 새로운 배열을 만든 후, 새로운 MyClass 객체를 생성합니다. obj2 객체는 obj1 객체의 깊은 복사본이므로, obj2.arr[0] = 4; 코드로 obj2의 arr 배열을 수정해도 obj1의 arr 배열은 영향을 받지 않습니다.

     

    또한, C#에서는 System.Object 클래스의 MemberwiseClone 메서드를 사용하여 얕은 복사를 수행할 수 있습니다. 다음은 MemberwiseClone 메서드를 사용하여 MyClass 클래스를 얕은 복사하는 예시 코드입니다.

    class MyClass {
        public int[] arr;
        public MyClass(int[] arr) {
            this.arr = arr;
        }
    
        public object ShallowCopy() {
            return (MyClass) this.MemberwiseClone();
        }
    }
    
    MyClass obj1 = new MyClass(new int[] { 1, 2, 3 });
    MyClass obj2 = obj1.ShallowCopy();  // 얕은 복사
    
    obj2.arr[0] = 4;
    Console.WriteLine(obj1.arr[0]);  // 출력: 4

    위 코드에서 MyClass 클래스는 ShallowCopy 메서드를 정의합니다. 이 메서드에서는 MemberwiseClone 메서드를 호출하여 현재 객체를 얕은 복사한 후, 캐스팅하여 반환합니다. obj2 객체는 obj1 객체의 얕은 복사본이므로, obj2.arr[0] = 4; 코드로 obj2arr 배열을 수정하면 obj1arr 배열도 같이 수정됩니다.

     

       obj1       obj2
    +--------+  +--------+
    |  arr   |  |  arr   |
    |--------|  |--------|
    |   -->--+--+-->     |
    |   [1]  |  |   [4]  |
    |   [2]  |  |   [2]  |
    |   [3]  |  |   [3]  |
    +--------+  +--------+

    위의 ASCII 아트는 obj1 객체와 obj2 객체를 깊은 복사할 때의 메모리 상태를 나타냅니다. obj1 객체는 { 1, 2, 3 } 배열을 참조하고 있습니다. obj2 객체를 obj1 객체로 깊은 복사하면, obj2 객체는 { 1, 2, 3 } 배열을 복사하여 새로운 배열을 참조합니다. 이 때, obj2.arr[0] = 4; 코드로 obj2 객체의 arr 배열을 수정해도, obj1 객체는 이 배열과는 다른 { 1, 2, 3 } 배열을 참조하고 있기 때문에 영향을 받지 않습니다.

     


    얕은 복사깊은 복사는 객체를 복사할 때 발생하는 문제를 해결하기 위해 사용됩니다. 얕은 복사는 객체의 참조만 복사하여, 두 객체가 같은 메모리를 참조하게 되는 반면, 깊은 복사는 객체의 모든 값을 복사하여, 두 객체가 서로 다른 메모리를 참조하게 됩니다.

    얕은 복사는 단순한 참조 복사로 메모리 절약에 유용하지만, 객체를 수정할 때 원하지 않는 부작용을 일으킬 수 있습니다. 따라서 객체를 수정할 일이 있거나, 복사한 객체의 값을 변경하더라도 원본 객체에 영향을 주지 않아야 하는 경우에는 깊은 복사를 사용해야 합니다.

     

    C#에서는 배열, 리스트, 객체 등을 복사하는 방법으로 얕은 복사와 깊은 복사를 모두 제공합니다. 배열과 리스트의 경우 Array.Clone() 메서드나 List<T>.CopyTo() 메서드를 사용하여 깊은 복사를 할 수 있습니다. 객체의 경우 MemberwiseClone() 메서드를 사용하여 얕은 복사를 할 수 있으며, IClonable 인터페이스를 구현하여 객체를 깊은 복사할 수 있습니다.

     

    알맞은 복사 방법을 선택하면 메모리 관리와 객체 수정 등의 문제를 효과적으로 해결할 수 있습니다.

     

    댓글

Designed by Tistory.