ProgramingTip

딥 카피와 얕은 카피의 차이점은 무엇입니까?

bestdevel 2020. 9. 29. 08:11
반응형

딥 카피와 얕은 카피의 차이점은 무엇입니까?


딥 카피와 얕은 카피의 차이점은 무엇입니까?


얕은 복사본은 가능한 한 적게 복제합니다. 컬렉션의 단순 복사본은 요소가 아닌 컬렉션 구조의 복사본입니다. 얕은 사본을 사용하면 이제 두 컬렉션이 식별 요소를 공유합니다.

딥 카피는 모든 것을 복제합니다. 컬렉션의 전체 복사본은 원본 컬렉션의 모든 요소가 복제 된 두 컬렉션입니다.


폭 대 깊이; 객체를 루트 노드로 사용하는 참조 트리의 관점에서 생각하십시오.

얕은 :

복사 전 얕은 복사 얕은 완료

변수 A와 B는 서로 다른 메모리 영역을 할당 며, B가 A에 할당 된 두 변수는 메모리 영역을 나타냅니다. 나중에 둘 중 하나의 내용을 수정하면 내용을 공유하는 다른 사람의 내용에 즉시 반영됩니다.

깊은 :

복사 전 딥 카피 깊은 완료

변수 A와 B는 메모리의 다른 영역을 할당하고, B가 A에 할당 된 A가 메모리 영역의 값이 할당됩니다. 나중에 내용에 대한 수정은 A 또는 B에 고유합니다. 내용은 공유되지 않습니다.


요컨대, 그것은 무엇을 대상에 달려 있습니다. 얕은 복사본에서 개체 B는 메모리에서 개체 A의 위치를 ​​가리. 딥 복사에서는 A의 메모리 위치에있는 모든 항목이 객체에서 복사됩니다.

이 위키 기사에는 훌륭한 다이어그램이 있습니다.

http://en.wikipedia.org/wiki/Object_copy


다음 이미지를 고려하십시오

여기에 이미지 설명 입력

예를 들어 Object.MemberwiseClone는 생성 얕은의 복사 링크를

및 사용 ICloneable 인터페이스 당신이 얻을 수있는 깊은 설명 된대로 사본을 여기에


특히 iOS 개발자의 경우 :

경우 BA는 얕은 복사A그 것처럼 원시 데이터를 다음 B = [A assign];과 같이의 개체에 대한 B = [A retain];

B와 A는 동일한 메모리 위치를 가리고 있습니다.

경우 BA는 딥 카피 의가 A, 다음은 같다B = [A copy];

B와 A는 다른 메모리 위치를 가리 킵니다.

B 메모리 주소는 A와 동일합니다.

B는 A와 같은 내용을 가지고 있습니다.


얕은 복사 : 한 개체에서 다른 개체로 멤버 값을 복사합니다.

전체 복사 : 한의 멤버 값을 다른 개체로 복사합니다.
                     모든 포인터 개체가 복제되고 딥 복사됩니다.

예 :

class String
{
     int   size;
     char* data;
};

String  s1("Ace");   // s1.size = 3 s1.data=0x0000F000

String  s2 = shallowCopy(s1);
 // s2.size =3 s2.data = 0X0000F000
String  s3 = deepCopy(s1);
 // s3.size =3 s3.data = 0x0000F00F
 //                      (With Ace copied to this location.)

여기에서 짧고 이해하기 쉬운 대답을 보지 못 시도해 보겠습니다.

얕은 복사본을 사용하면 원본이 모든 개체도 대상으로 지정되지 않은 개체가 복사됩니다.

전체 복사를 사용하면 원본이 모든 개체가 복사되고 복사본은 대상이 된 것입니다 (이제 참조 각 개체가 2 개가됩니다). 이것은 오브젝트 트리에서 반복됩니다.


이해를 쉽게하기 위해 https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm 문서를 따를 수 있습니다.


얕은 복사 :

얕은 복사


딥 카피 :

딥 카피


{두하고 상상을 상상해보세요 : A와 B가 같은 유형 _t (C ++와 관련된 생각)이고 A에서 B 로의 얕은 / 깊은 복사에 대해 설명합니다}

Shallow Copy : A에 대한 참조의 사본을 B로 만듭니다. A의 주소 사본이라고 생각하면됩니다. 따라서 A와 B의 주소는 동일합니다. 즉, 동일한 메모리 위치, 즉 데이터 내용을 가리 킵니다.

전체 복사 : A의 모든 구성원을 복사하고 B의 다른 위치에 메모리를 할당 한 다음 복사 된 구성원을 B에 할당하여 전체 복사를 수행합니다. 이런 식으로 A가 존재하지 않는 경우 B는 여전히 메모리에서 유효합니다. 사용할 올바른 용어는 복제입니다. 둘 다 완전히 동일하지만 다른 것 (즉, 메모리 공간에 두 개의 다른 하나의 저장 됨)을 알고 있습니다. 포함 / 제외 목록을 통해 전체 복사 중에서 선택할 속성을 선택할 수있는 복제 래퍼를 제공 할 수도 있습니다. 이것은 API를 만들 때 매우 일반적인 관행입니다.

관련된 이해 관계를 이해 한 경우 에만 얕은 복사를 선택할 수 있습니다 . C ++ 또는 C에서 처리 할 포인터가 엄청나게 많을 때 개체의 얕은 복사를 수행하는 것은 나쁜 생각입니다.

EXAMPLE_OF_DEEP COPY_ 예를 들어, 이미지 처리 및 인식을 수행 할 때 처리 영역에서 "무관하고 반복적 인 동작"을 가려야 합니다. 이미지 포인터를 사용하는 경우 해당 마스크 이미지를 저장할 수 있습니다. NOW ... 이미지의 얕은 복사본을 수행하면 포인터 참조가 스택에서 제거 될 때 참조와 해당하는 사본이 축소됩니다. 즉, 액세스 위반의 작동 오류가 발생합니다. 이 경우 필요한 복제하여 이미지의 깊은 사본입니다. 이렇게하면 나중에 필요할 때 마스크를 검색 할 수 있습니다.

EXAMPLE_OF_SHALLOW_COPY 저는 StackOverflow의 사용자에 비해 많은지 지식이 있습니다. 부분을 자유롭게 삭제하고 좋은 예를 찾을 수 있습니다. 하지만 프로그램이 무한한 시간 동안 실행될 수있는 것을 알고 있다고 생각합니다. 즉, 함수 호출로 스택을 통해 연속 "푸시 팝"작업을 수행합니다. (예 : C / C ++ 튜토리얼 자료) 괜찮습니다. 그러나 감시 및 감지 시스템이나 Sonar Tracking System과 같은 응용 프로그램을 실행하는 경우 조만간 프로그램을 죽일 수 있으므로 개체를 얕게 복사 할 수 있습니다.


char * Source = "Hello, world.";

char * ShallowCopy = Source;    

char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);        

'ShallowCopy'는 'Source'와 동일한 메모리 위치를 가리 킵니다. 'DeepCopy'는 메모리의 다른 위치를 가리 키지 만 내용은 동일합니다.


얕은 복사 란 무엇입니까?

얕은 복사본은 개체의 비트 단위 복사본입니다. 원래 개체의 값과 정확히 일치하는 새 개체가 만들어집니다. 객체의 필드 중 하나가 다른 객체에 대한 참조 인 경우 참조 주소 만 복사됩니다. 즉, 메모리 주소 만 복사됩니다.얕은 복사

이 그림 에서이 MainObject1필드가 field1int 형, 그리고 ContainObject1유형을 ContainObject. 당신의 단순 복사본을 수행 할 때 MainObject1, MainObject2생성되는 field2복사 된 값을 field1여전히 포함하고 ContainObject1있습니다. 이후 field1는 그 값이 복사 되지만 field2이후는 ContainedObject1, 목적은 MainObject2여전히 가리는 형태의 원시 ContainObject1. 에 대한 변경 그래서 ContainObject1MainObject1반영 MainObject2됩니다.

이제 이것이 얕은 카피라면 딥 카피가 무엇인지 볼까요?

딥 카피 란 무엇입니까?

전체 복사는 모든 필드를 복사하고 할당 메모리의 복사본을 만듭니다. 전체 복사는 개체가 참조하는 개체와 함께 복사 될 때 발생합니다.딥 카피

이 그림에서 MainObject1은 필드가 field1int 형, 그리고 ContainObject1유형을 ContainObject. 당신의 깊은 사본을 수행 할 때 MainObject1, MainObject2생성되는 field2복사 된 값을 포함 field1하고 ContainObject2의 복사 된 값을 포함 ContainObject1합니다. ContainObject1에서 변경 한 사항은 MainObject1반영되지 않습니다 MainObject2.

좋은 기사


프로그래밍 지향 프로그래밍에서 유형에는 멤버 필드 모음이 포함됩니다. 대신 필드는 값 또는 참조 (즉, 값에 대한 포인터)로 저장 될 수 있습니다.

단순 복사에서는 유형의 새 인스턴스가 작성되고 값이 새 인스턴스에 복사됩니다. 참조 포인터도 값처럼 복사됩니다. 따라서 참조는 원본 개체를 가리 킵니다. 참조에 의해 악성 멤버에 대한 모든 변경 사항은 참조 된 개체에 대한 복사본이 만들어지지 갑자기 기 원본과 복사본 모두에 나타납니다.

전체 복사에서 값으로 저장된 필드는 이전과 같이 복사는 참조로 복사 개체에 대한 포인터는 복사합니다. 대신 참조 된 개체로 전체 복사본이 만들어지고 새 개체에 대한 포인터가 저장됩니다. 참조 된 객체를 변경해도 수업의 다른 클래스에 영향을줍니다.


'ShallowCopy'는 'Source'와 동일한 메모리 위치를 가리 킵니다. 'DeepCopy'는 메모리의 다른 위치를 가리 키지 만 내용은 동일합니다.


얕은 복제 :
정의 : "개체의 얕은 복사본은 '주'개체를 복사하지만 내부 개체는 복사하지 않습니다." 사용자 지정 개체 (예 : Employee)에 기본 홈페이지 유형 변수 만있는 경우 Shallow Cloning을 사용합니다.

Employee e = new Employee(2, "john cena");
Employee e2=e.clone();

super.clone();재정의 된 clone () 메서드로 반환 하면 작업이 끝납니다.

Deep Cloning :
정의 : "얕은 복사본과 달리 전체 복사본은 개체의 완전히 제거 된 인 복사본입니다."
직원이 다른 사용자 지정 개체를 보유하는 경우를 의미합니다.

Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");

그런 다음 재정의 된 clone () 메서드 'Address'개체를 복제하는 코드를 작성해야합니다. 국제적인 주소 개체가 복제되지 않고 복제 된 직원 개체에서 주소 값을 설명 할 때 버그가 발생합니다. 이것은 원본도 반영합니다.


var source = { firstName="Jane", lastname="Jones" };
var shallow = ShallowCopyOf(source);
var deep = DeepCopyOf(source);
source.lastName = "Smith";
WriteLine(source.lastName); // prints Smith
WriteLine(shallow.lastName); // prints Smith
WriteLine(deep.lastName); // prints Jones

딥 카피

전체 복사는 모든 필드를 복사하고 할당 메모리의 복사본을 만듭니다. 전체 복사는 개체가 참조하는 개체와 함께 복사 될 때 발생합니다.

얕은 복사

얕은 복사본은 개체의 비트 단위 복사본입니다. 원래 개체의 값과 정확히 일치하는 새 개체가 만들어집니다. 개체의 필드 중 하나가 다른 개체에 대한 참조 인 경우 참조 주소 만 복사됩니다. 즉, 메모리 주소 만 복사됩니다.


얕은은 복사 -원본 및 얕은 복사 된 개체 내부의 참조 변수에는 공통 개체에 대한 참조가 있습니다.

전체 복사 -원본 및 전체 복사 된 개체 내부의 참조 변수는 다른 개체에 대한 참조를 사용 합니다.

복제는 항상 얕은 복사를 수행합니다.

public class Language implements Cloneable{

    String name;
    public Language(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

메인 클래스는

public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{

      ArrayList<Language> list=new ArrayList<Language>();
      list.add(new Language("C"));
      list.add(new Language("JAVA"));

      ArrayList<Language> shallow=(ArrayList<Language>) list.clone();
      //We used here clone since this always shallow copied.

      System.out.println(list==shallow);

      for(int i=0;i<list.size();i++)
      System.out.println(list.get(i)==shallow.get(i));//true

      ArrayList<Language> deep=new ArrayList<Language>();
      for(Language language:list){
          deep.add((Language) language.clone());
      }
      System.out.println(list==deep);
      for(int i=0;i<list.size();i++)
          System.out.println(list.get(i)==deep.get(i));//false

} 

위의 출력은 다음과 가변합니다.

거짓 참 참

거짓 거짓 거짓

원래 개체에서 변경된 사항은 깊은 개체가 아닌 얕은 개체에 반영됩니다.

  list.get(0).name="ViSuaLBaSiC";
  System.out.println(shallow.get(0).getName()+"  "+deep.get(0).getName());

출력 -ViSuaLBaSiC C


공식적인 정의보다는 예를 들어보고 싶습니다.

var originalObject = { 
    a : 1, 
    b : 2, 
    c : 3,
};

이 코드는 얕은 사본을 보여줍니다 .

var copyObject1 = originalObject;

console.log(copyObject1.a);         // it will print 1 
console.log(originalObject.a);       // it will also print 1 
copyObject1.a = 4; 
console.log(copyObject1.a);           //now it will print 4 
console.log(originalObject.a);       // now it will also print 4

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // now it will print 1

이 코드는 딥 카피를 보여줍니다 .

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // !! now it will print 1 !!

struct sample
{
    char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
    dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
    dest.ptr=malloc(strlen(src.ptr)+1);
    memcpy(dest.ptr,src.ptr);
}

간단히 말해서 Shallow Copy는 Call By Reference와 유사하고 Deep Copy는 Call By Value와 유사합니다.

참조로 호출에서 함수의 형식 및 고유 한 메모리 위치와 값을 참조합니다.

Call By Value에서 함수의 형식 및 실제 변수는 모두 다른 메모리 위치를 참조하지만 동일한 값을가집니다.


arr1과 arr2라는 두 개의 배열이 상상해.

arr1 = arr2;   //shallow copy
arr1 = arr2.clone(); //deep copy

단순 복사는 새로운 복합 객체를 생성하고 그 참조를 객체에 삽입합니다.

얕은 복사와 달리 deepcopy는 새로운 복합 개체를 생성하고 복합 개체의 원본 개체의 복사본도 삽입합니다.

예를 들어 보겠습니다.

import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)

위의 코드는 FALSE를 인쇄합니다.

방법을 보자.

원래 복합 개체 x=[1,[2]](개체 내부에 개체가 있기 때문에 합성이라고 함 (Inception))

여기에 이미지 설명 입력

이미지에서 볼 수 목록 안에 목록이 있습니다.

그런 다음을 사용하여 얕은 복사본을 만듭니다 y = copy.copy(x). 여기서는 그곳에서 새로운 복합 객체를 생성하지만 그 안에있는 객체를 생성합니다.

여기에 이미지 설명 입력

이미지에서 외부 목록에 대한 새 사본을 작성했습니다. 그러나 내부 목록은 원래 목록과 동일하게 유지됩니다.

이제 우리는 z = copy.deepcopy(x). 여기서는 그곳에서 할 일 외부 목록과 내부 목록에 대한 새 객체를 생성하는 것입니다. 아래 이미지와 같이 (빨간색 강조 표시).

여기에 이미지 설명 입력

마지막 코드는 Falsey와 z가 같은 현상이 아니기 때문에 인쇄 합니다.

HTH.


단순 복사는 새 object-를 만든 다음 현재 object-의 non-정적 필드를 새 object-에 복사하는을 구석으로입니다. 필드가 값 유형 인 경우-> 필드의 비트 단위 복사가 수행됩니다. A에 대한 기준 입력 -> 참조 복사 언어 입력 ; 따라서 원본 개체와 해당 개체를 참조합니다.

전체 복사는 새 개체를 만든 다음 현재 개체의 비 정적 필드를 새 개체에 복사하는 것입니다. 필드가 값 유형 ->이면 필드의 비트 단위 복사가 수행됩니다. 필드가 참조 유형 인 경우 -> 참조 된 객체의 새 복사본이 수행됩니다. 복제 할 클래스는 [Serializable]로 표시되어야합니다.


[블로그]에서 발췌 : http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

전체 복사 에는 한 개체의 내용을 사용하여 동일한 클래스의 다른 인스턴스를 만드는 작업이 포함됩니다. 전체 복사에서 두 개체는 동일한 정보를 포함 할 수 있고 대상 개체에는 자체 버퍼와 리소스가 있습니다. 두 개체의 파괴는 나머지 개체에 영향을 미칠 수 있습니다. 오버로드 된 할당 연산자는 개체의 전체 복사본을 만듭니다.

얕은 복사 는 한 객체의 내용을 동일한 클래스의 다른 인스턴스로 복사하여 미러 이미지를 만드는 것을 포함합니다. 참조 및 내용의 공유 복사로 인해 두 개체는 예측할 수있는 다른 개체의 동일한 외부 포함됩니다.

설명 :

복사 생성 기능을 사용하여 멤버별로 데이터 값을 간단히 복사합니다. 이 복사 방법을 얕은 복사라고합니다. 객체가 내장되어 구성되고 포인터가없는 단순한 클래스 인 경우 허용됩니다. 이 함수는 값과 객체를 사용하며 그 동작은 얕은 복사로 변경되지 않습니다., 주소가 수신 값이 아닌 멤버 인 포인터의 주소 만 복사됩니다. 수업의 데이터 값이 함수에 의해 실수로 변경됩니다. 함수가 범위를 벗어나면 모든 데이터가 팝되는 복사본이 스택에서 발생합니다.

객체에 포인터가있는 경우 전체 복사를 실행해야합니다. 무료 저장소의 전체 복사를 사용하면 할당되고 할당 된 요소가 복사됩니다. 함수에서 반환되는 개체에 대해 전체 복사가 사용됩니다.


다른 답변에 더 추가 비용

  • 유형의 Shallow Copy는 값 유형 기반 속성에 대한 값별 복사를 수행하고 참조 기반 속성에 대한 참조 별 복사를 수행합니다.
  • 객체의 전체 복사는 값 유형 기반 속성에 대한 값별 복사를 수행하고 계층 구조 (참조 유형의) 깊은 참조 유형 기반 속성에 대한 값별 복사를 수행합니다.

얕은 복사는 새 참조를 생성하지 않지만 전체 복사는 새 참조를 생성합니다.

다음은 딥 카피와 얕은 카피를 설명하는 프로그램입니다.

public class DeepAndShollowCopy {
    int id;
    String name;
    List<String> testlist = new ArrayList<>();

    /*
    // To performing Shallow Copy 
    // Note: Here we are not creating any references. 
      public DeepAndShollowCopy(int id, String name, List<String>testlist)
       { 

       System.out.println("Shallow Copy for Object initialization");
       this.id = id; 
       this.name = name; 
       this.testlist = testlist; 

       }
    */  

    // To performing Deep Copy 
    // Note: Here we are creating one references( Al arraylist object ). 
    public DeepAndShollowCopy(int id, String name, List<String> testlist) {
        System.out.println("Deep Copy for Object initialization");
        this.id = id;
        this.name = name;
        String item;
        List<String> Al = new ArrayList<>();
        Iterator<String> itr = testlist.iterator();
        while (itr.hasNext()) {
            item = itr.next();
            Al.add(item);
        }
        this.testlist = Al;
    }


    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Oracle");
        list.add("C++");
        DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
        System.out.println(copy.toString());
    }
    @Override
    public String toString() {
        return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
    }
}

ararys 복사 :

array1 = array2는 배열을 참조하는 두 개의 변수를 생성합니다.

그러나이 예를 들어.

  static void Main()
    {
        int[] arr1 = new int[] { 1, 2, 3, 4, 5 }; 
        int[] arr2 = new int[] { 6, 7, 8, 9, 0 };

        Console.WriteLine(arr1[2] + " " + arr2[2]);
        arr2 = arr1;
        Console.WriteLine(arr1[2] + " " + arr2[2]); 
        arr2 = (int[])arr1.Clone();
        arr1[2] = 12;
        Console.WriteLine(arr1[2] + " " + arr2[2]);
    }

얕은 복제 는 복제 된 배열이 배열이 메모리 만 복사됨을 의미합니다.

배열에 값이 있으면 비용이 들게 보내 주시면 됩니다.

배열에 참조 유형이 포함 된 경우 참조 만 복사됩니다. 따라서 구성원이 객체를 참조하는 두 개의 배열이 있습니다 .

참조 유형이 복제되는 전체 복사본을 만들려면 배열을 반복하고 요소를 수동으로 복제해야합니다.


나는 다음 줄에서 이해하게 예.

얕은 복사는 객체 값 유형 (int, float, bool) 필드를 대상 객체에 복사하고 객체의 참조 유형 (문자열, 클래스 등)은 대상 객체의 참조복사 됩니다. 이 대상에서 참조는 소스 개체의 메모리 위치를 가리 유형입니다.

전체 복사는 객체의 값과 참조 유형을 대상의 완전히 새로운 사본으로 복사합니다. 이는 값 유형과 참조 유형 모두에 새 메모리 위치가 할당됨을 의미합니다.


위의 모든 정의에 더하고 가장 일반적으로 사용되는 깊은 복사는 클래스의 복사 생성자 (또는 오버로딩 할당 연산자)에 있습니다.

Shallow copy->는 복사 생성시 제공되지 않는 경우입니다. 여기에서는 모든 멤버가 복사되는 클래스의 모든 멤버가 복사됩니다.

Deep copy->는 클래스에서 복사 생성자 또는 오버로드 할당을 구현하고 클래스의 모든 멤버를 복사 할 수 있도록 결정한 경우입니다.

MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
          // write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
          // write your code, to copy all the members and return the new object
}

복사 생성자는 이전에 생성 된 동일한 클래스의 객체로 새 객체를 초기화하는 데 사용됩니다. 기본적으로 컴파일러는 얕은 복사본을 작성했습니다. 얕은 복사는 동적 메모리 할당이 관련되지 않은 경우 잘 작동합니다. 동적 메모리 할당이 관련 널 두 객체가 힙의 동일한 메모리 위치를 가리 키기 때문입니다. 따라서 두 가지 모두 고유 한 속성 사본을 갖도록 딥 복사를 작성했습니다. 기억에. 전체 예제와 설명이 포함 된 세부 정보를 기사를 참조하십시오 C ++ 생성자 기사를 참조하십시오 .

참고 URL : https://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy

반응형