진짜 가고 싶었던 게임사 1차 면접에서 복사 생성자가 무엇인가에 대해 나왔습니다.

이 용어 자체를 잘몰라서 잘모르겠다고 대답했고, 이어서 얕은 복사와 깊은 복사에 대해 물어보셨습니다.

두 용어가 헷갈리긴 했지만, 무엇을 뜻하는지는 기억이 나서 잘 대답했던 경험이 있네요.

어쨋든 면접에서 나온 내용을 복습하고자 합니다!! 복사생성자!!!!!!

얕은 복사와 깊은 복사는 복사 생성자의 사전 지식입니다. 모르시면 찾아서 공부하고 참고해주세요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
 
class test {
public:
    char* name;
    int score;
 
    test(const char* name, int score) {
        this->score = score;
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
    }
 
    void print() {
        cout << this->score << '\n';
        cout << this->name << '\n';
    }
 
    void nameDelete() {
        delete name;
    }
};
 
 
int main(void)
{
    test a("홍길동"30);
    a.print();
 
    test b = a;//얕은 복사 발생
    b.print();
    
    printf("%x\n", b.name);
    printf("%x\n", a.name);
 
    a.nameDelete();
 
    a.print();
    b.print();
    return 0;
}
cs



이 코드의 결과는

30

홍길동

30

홍길동

28e030

28e030

30

硼硼硼硼硼硼硼硼3쬋왹

30

硼硼硼硼硼硼硼硼3쬋왹


가 출력이 될것입니다.

홍길동 밑의 16진수와 아래의 깨지는 문자열은 다르게 출력될 수 있습니다.


이렇게 출력되는 이유에 대해서 알려드리겠습니다.

어떤 클래스의 객체에서 =을 이용하여 객체의 값을 복사하려고 할 때(대입할 때) 따로 오버라이딩을 하지 않는다면

해당 변수의 값만 복사됩니다.

이게 무슨말이냐하면..


위의 test클래스에는 name과 score가 있습니다.

근데 디폴트(오버라이딩을 하지 않았을 떄)

test b = a;

를 실행하면 발생되는 코드는

b.name = a.name;

b.score = a.score;


입니다.


이게 무슨 문제일까요?

네 문제입니다.

왜냐하면 name은 문자열이기 때문입니다. a.name과 b.name은 문자열 자체를 저장하는 것이 아닌 해당 문자열의 시작 주소를 저장하고 있습니다.

그러므로 포인터이겠죠. "홍길동"이라는 새로운 인스턴스가 생성되서 b에 대입되는 것이 아닌, a의 "홍길동"을 같이 가르키게 되는 것입니다.


이게 왜 문제인지 또 모르실 수 있습니다. 이 문제는 위에서 출력된 깨진 문자열을 보시면 됩니다.

문자열이 깨진 이유는 a.nameDelete();을 실행했기 때문입니다. 이것은 함수명 그대로 name에 할당한 메모리를 지워버립니다.

그렇다면.. a의 문자열 "홍길동"이 지워지면 b의 문자열 "홍길동"도 같이 지워지는 것입니다.

(엄연히 따지면 b의 문자열이 아니고 a와 b는 같은 메모리를 가르키고있음)


이를 해결하기 위해서는 복사생성자를 오버라이딩하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
 
class test {
public:
    char* name;
    int score;
 
    test(const char* name, int score) {
        this->score = score;
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
    }
 
    void print() {
        cout << this->score << '\n';
        cout << this->name << '\n';
    }
 
    //복사생성자 오버라이딩
    test(const test &T) {
        score = T.score;
        name = new char[strlen(T.name) + 1];
        strcpy(name, T.name);
    }
 
    void nameDelete() {
        delete name;
    }
};
 
 
int main(void)
{
    test a("홍길동"30);
    a.print();
 
    test b = a;//얕은 복사 발생
    b.print();
 
    printf("a.name이 가리키는 주소 : %x\n", a.name);
    printf("b.name이 가리키는 주소 : %x\n", b.name);
 
    a.nameDelete();
 
    a.print();
    b.print();
    return 0;
}
 
cs


위의 주석 부분 //복사생성자 오버라이딩 부분을 추가해주시면 해결할 수 있습니다.(이로써 깊은 복사가 되는 것이다!)


위 코드의 출력은

30

홍길동

30

홍길동

a.name이 가리키는 주소 : 10ddc8

b.name이 가리키는 주소 : 10da80

30

硼硼硼硼硼硼硼硼?k멓

30

홍길동


입니다.


위의 예제와는 다르죠??

a.name과 b.name이 가리키는 주소가 다릅니다.

이는 복사를 할 때 우리가 오버라이딩한대로 실행되기 때문입니다.

단순히 a.name이 가리키는 값을 복사하는 것이 아닌 새로 동적할당을 하여 문자열을 새로만들고 그 주소를 b.name에 대입을 하는 것입니다.


그리고 a.name만 삭제했기 떄문에 그대로 b는 살아있을 수 있는거죠!!!!!!!!!!!!!!!!


이만 포스팅을 마치겠습니다. 궁금한 점은 댓글달아주세요 ^^


ps....

근데 cpp의 string클래스를 사용하면 그냥 알아서 값을 복사해주더라구요..ㅎㅎㅎ..엄청 편리합니다..

'언어, git > C++' 카테고리의 다른 글

Const(상수) 선언 위치  (0) 2019.03.26
가상함수?  (0) 2017.11.19

+ Recent posts