티스토리 뷰
https://www.youtube.com/watch?v=cz7LH28nomc
위 널널한개발자 님의 C++ 강의를 듣고, 저의 생각을 정리한 포스팅 입니다.
1. 왜 C++랑 Python을 비교하는가?
둘다 Base가 C 이기 때문입니다(CPython 한정).
물론, C++은 C와 Base가 유사하지, C와 완전 같은 compiler를 쓰진 않습니다.
그래도, 두 언어의 Base가 C라는 유사점, C의 생산성을 높인 스타일을 언어라는 점에서 비교하면 좋겠다고 생각이 들었습니다.
2. C++의 생성자
C++은 C언어와 동일하게 포인터를 사용합니다.
때문에, Class 멤버역시 포인터로 선언이 가능합니다.
이때, 이 포인터형식의 Class멤버일 경우 문제가 발생할 수 있습니다.
아래 예제를 보시죠
#include <iostream>
using namespace std;
class temp_cls
{
public:
temp_cls(){
pro_a = new int(5);
printf("temp object created\n");
}
~temp_cls(){
delete pro_a;
printf("temp object removed");
}
int *pro_a;
};
int main()
{
temp_cls test;
temp_cls *temp = &test;
temp_cls *temp2(temp);
cout << (*temp).pro_a << endl;
cout << (*temp2).pro_a << endl;
delete temp;
printf("test val %p",(*temp2).pro_a);
return 0;
}
/*
temp object created
a.b와 b.b가 동일한 위치를 Pointing하고 있는것을 볼 수 있습니다
0x56502926aeb0
0x56502926aeb0
double free or corruption (out)
*/
C++ 는 object2(object1)와 같은 방식으로 복사를 지원합니다.
이때 object2는 별도의 복사생성자가 없다면 object1의 Class Properties를 모두 복사해 옵니다.
대신, C++의 Property의 type은 무시하고 그냥 복사를 하기 때문에, Pointer의 경우 얕은복사가 발생합니다.
따라서 temp가 삭제되면서 temp.pro_a의 할당이 해제되고, 이후에 temp2.prob에 접근하게 된다면 delete된 pro_a를 한번더 메모리해제가 일어나서 메모리 접근에 오류가 발생합니다.
(위 처럼 따로 접근을 하지 않더라도, main function이 끝나면서 temp할당 해제 -> temp2할당 해제 과정에서 역시 메모리 접근 오류가 발생합니다)
그래서, C++같은 경우는
1. 일반 생성자
2. 복사 생성자(C++의 복사 syntax시 행동할 함수)
3. 대입 연산자(복사생성자와 유사하나, 복사생성자를 구현한다면 무조건 구현해줘야됨)
4. 변환 생성자(생성자가 매개변수를 1개만 받는 경우->요 경우 해당 매개변수 1개만 넣어주면 자동으로 형변환이 일어나게 설정되는 것이기 때문에 변환 생성자라고함. 좀 내용이 복잡한데, 아래 IBM의 공식문서를 읽으시면 이해가 편합니다.)
https://www.ibm.com/docs/en/i/7.1?topic=only-conversion-constructors-c
와 같이 다양한 생성자를 정의해 줘야 합니다.
아래의 예시를 보시면 빠르게 이해가 갈 것이라고 생각합니다.
#include <iostream>
using namespace std;
class temp_cls
{
public:
temp_cls(void){
pro_a = new int(5);
printf("temp object %p created\n", this);
}
//int value를 받을 때 대응될 변환생성자
explicit temp_cls(int a){
this->pro_a = new int(a);
printf("temp object %p created by trasnform init\n", this);
}
//clss object를 받을 경우의 복사생성자
explicit temp_cls(const temp_cls &tg_obj){
printf("temp object %p created\n", this);
printf("receive temp_cls object. tg_obj a : %d\n", *tg_obj.pro_a);
this->pro_a = new int (*tg_obj.pro_a);
}
//class pointer를 받을 경우의 복사생성자
explicit temp_cls(temp_cls *tg_obj){
printf("temp object %p created\n", this);
printf("receive temp_cls pointer. tg_obj a : %d\n", *(*tg_obj).pro_a);
this->pro_a = new int(*(tg_obj->pro_a));
}
~temp_cls(){
delete pro_a;
printf("temp object %p removed\n", this);
}
//class object간 =연산을 통해서 복사할 경우
temp_cls &operator =(const temp_cls &tg_obj){
printf("temp object %p created\n", this);
printf("receive temp_cls object by operator '='. tg_obj a : %d\n", *tg_obj.pro_a);
this->pro_a = new int (*tg_obj.pro_a);
return *this;
}
int *pro_a;
};
int main()
{
temp_cls test123;
temp_cls test(10);
temp_cls test_op(30);
test_op = test;
temp_cls *temp = new temp_cls(test);
temp_cls *temp2 = new temp_cls(temp);
cout << (*temp).pro_a << endl;
cout << (*temp2).pro_a << endl;
delete temp;
printf("test val %p is alive \n",(*temp2).pro_a);
return 0;
}
/*
(test123 obj)temp object 0x7ffe49d54740 created
(test obj)temp object 0x7ffeb6649a68 created by trasnform init
(test_op obj)temp object 0x7ffeb6649a70 created by trasnform init
(test_op obj =operation)temp object 0x7ffeb6649a70 created
(test_op obj =operation)receive temp_cls object by operator '='. tg_obj a : 5
(temp pointer)temp object 0x55954cd76320 created
(temp pointer)receive temp_cls object. tg_obj a : 5
(temp2 pointer)temp object 0x55954cd76360 created
(temp2 pointer)receive temp_cls pointer. tg_obj a : 5
0x55954cd76340
0x55954cd76380
(temp pointer)temp object 0x55954cd76320 removed
(temp2 pointer)test val 0x55954cd76380 is alive
(test pointer)temp object 0x7ffeb6649a70 removed
(test_op pointer)temp object 0x7ffeb6649a68 removed
*/
3. Python을 Class 생성자
Python의 경우 다양한 생성자를 지원하지않고, 매우 단순한 생성자만 지원합니다.
class temp_cls:
def __init__(self, a=None, b=None):
self.a = a
self.b = b
import copy
if __name__ == "__main__":
temp = temp_cls(1, [20,54,62,3,9])
#C++의 temp_cls temp2(temp);
#를 얕은복사 형식으로 사용한것과 같은 기능을 합니다.
temp2 = copy.copy(temp)
print(temp is temp2)
print(temp.b is temp2.b)
del temp
print(temp2.b)
'''
temp과 temp2가 같은지 여부 : False
temp.b와 temp2.b가 같은지 여부 : True
temp를 삭제한 뒤 temp2.b : [20, 54, 62, 3, 9]
'''
차이점이 보이시나요?
파이썬의 경우 복사생성자가 따로 존재하지 않지만, copy 라는 내장 라이브러리를 통해서 동일한 기능이 구현 가능합니다.
이때, Python과 C++의 차이점이 발생합니다.
Python의 List객체는 C++의 포인터처럼 Mutable하고 해당 주소를 통해 접근하는 객체 입니다.
위 예제에서 보면 temp2가 temp을 복사해서 받으면서 temp.b와 temp2.b가 바라보는 객체는 같은 걸 알수 있습니다.
만약 C++이었다면 위 상황에서 temp를 delete해서 날려버린다면?
temp.b역시 메모리가 해제되고, temp2.b로 접근할 때 메모리 접근 오류가 발생할 것입니다.
하지만, Python의 Garbage Collection 덕분에 해당 변수는 아직 Reference Count가 남아있고,
temp2가 삭제되기 전까지 무사히 유지될 수 있습니다.
덕분에 C++에서 존재하는 여러가지 생성자를 프로그래머가 고민할 필요 없이 사용이 가능한 것이라고 볼 수 있습니다.
'C언어 잡기술 > C++' 카테고리의 다른 글
상속에 관해서 (0) | 2022.05.19 |
---|---|
C++에는 있고, C언어에는 없는것 (0) | 2022.05.14 |
- Total
- Today
- Yesterday
- git
- 완전탐색 알고리즘
- Search알고리즘
- 사칙연산
- GDC
- 병렬처리
- 컴퓨터그래픽스
- Greedy알고리즘
- SIMD
- 프로그래머스
- heap
- Sort알고리즘
- Python
- AVX
- stack
- C++
- prime number
- 분할정복
- 코딩테스트
- 자료구조
- 동적계획법
- 이분탐색
- hash
- 알고리즘
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |