얕은 복사와 깊은 복사 그리고 참조 카운팅

보물창고·2022년 8월 16일
0

c++ basic 코드누리

목록 보기
29/50

업데이트 240821

: 복사가 이루어지는 클래스에 포인터가 있다면,
얕은복사에 대비해서 반드시 유저는 복사 생성자를 따로 만들어서
깊은 복사가 가능한 코드를 작성해야 한다.

  • 이렇게 하지 않으면 이중 해제가 발생한다. 그리고 하나의 포인터만 참조하게 되는 문제다.

얕은 복사

  • 아래 얕은복사로 인해 포인터가 있는 클래스는 유저가 직접 복사생성자를 구현해야 한다.

이 표현이 정확할 듯.
: 객체 복사 시, 멤버 포인터의 참조값뿐 아니라, 포인터까지 복사하는 현상
-> 해제시에 2개의 소멸자에서 동일한 포인터를 2번 해제하기 때문에
메모리 릭이 발생한다.

>
쉽게
: 서로 다른 객체의 멤버가 동일한 포인터를 복사하는 것을 말함.
// 값이 아니라 동일한 메모리를 참조하게 됨.

  • 디폴트 복사 생성자의 특징
    : 디폴트 복사 생성자는 모든 멤버 데이터간의 복사 대입을 이루어지게 함.

  • 문제점
    : 클래스에 포인터가 존재하고, 소멸자에서 해제하는 코드가 존재시
    동일한 포인터를 2번 해제하게 됨.

  • 해결하는 방법

  1. 깊은복사
  2. 참조 계수 사용
  • 결과
    : 이미 해제된 메모리를 또 해제하므로 오류 발생함.

problem

: 위의 내용을 토대로 클래스를 만들고, 얕은 복사 문제를 발생시켜라

  • char* , int 가 있는 Student 클래스를 만들어라.
  • 이어서 객체 p를 만들고, 1, "bomi"를 main에서 인자로 보내자.
    : Student 생성자에서 bomi 받을 때는 상수니까
    const char* 로 받아야 겠지?
  • 이어서 객체 p2에다가 p를 대입하자.
  • 추가로 소멸자도 만들어서 해제하는 코드 만들자.

-> 동일한 메모리의 주소를 공유하고 있고, 메모리 2번 해제하므로
문제 발생함.

  • 힌트 strcpy 사용. , char 할당 시 null 문자까지 포함하도록
  • 힌트 : #pragma는 strpy 문제 해결하기 위해 선언해줌.

얕은 복사를 해결하는 2가지 방법.

1. 깊은 복사

쉽게
서로 다른 객체의 멤버가 동일한 포인터가 아닌, 새로운 포인터를 할당 후,
값을 복사 하게 하는 복사를 말함.

어렵게
: 클래스 안에 포인터 멤버가 있을 때, "메모리 주소를 복사하지 말고, 메모리
자체의 복사본을 만드는 기술"
(유저가 복사 생성자를 직접 정의 해야함. )

처리하기

  • 포인터를 새롭게 할당해서 참조값을 대입하자.
  • 일반값은 바로 대입.
    -> 일반값은 이니셜라이저로 초기화하도록 하자.

깊은 복사의 문제

: 메모리 낭비.

problem

: Student 에서 발생한 문제를 해결하라.

2. 참조 계수 사용

설명
: 여러 객체가 공유하는 포인터 변수를 하나 만들어서,
복사 생성시 카운팅을 통해 얕은 복사를 해결하는 것을 말함.

주의할 점.
이때 일반생성자에서는 할당을 하고, 복사가 일어날 경우, 포인터 변수를
대입함으로써, 여러개의 객체가 단 하나의 메모리를 공유하도록 하자.
소멸자에서 포인터 변수를 확인하면서 , 모든 객체 제거시
카운팅 0 일때 포인터 변수를 해제하는 방법.

  • 카운팅 갯수의 의미는 참조하고 있는 객체의 갯수를 나타냄.

  • 여러 객체가 하나의 자원을 공유함.

problem

: 참조 카운팅을 만들어라

  • 클래스만 캡처함.
    : 이때는 포인터인 name도 복사해버림.
  • 최근에 작성한 코드
    : 230302

profile
🔥🔥🔥

0개의 댓글