최근에 컴퓨터 그래픽스 공부를 하고 싶어서 C++를 배우고 있다. 포인터를 공부하다가 의문이 들었다. 굳이 이걸 쓰는 이유가 뭘까? 그 의문은 아래와 같은 예에서 시작했다.
자바의 경우 이런식으로 하면 끝나는 코드인데...
public MyClass create() {
return new MyClass();
}
public static void main(String[] args) {
MyClass c = create();
}
음... C++에서 똑같이 해도 되는걸까?
MyClass create() {
return MyClass(); // 스택에 생성된 객체 반환
}
int main() {
MyClass c = create();
}
되는거 같은데....? 그래서 GPT선생님께 물어봤다. 답은 위의 예에서 자바의 경우는 내가 만든 MyClass
가 처음부터 heap에 생성되지만, cpp에서 만든 MyClass
는 stack에 생성된다는 것이었다. create 함수가 종료되면 이것은 깊은 복사(그러니까 새로운 MyClass를 하나 만든다는 소리)를 heap에 만들고 main 함수의 c로 전달이 된다.
아.... 그러니까 되긴 되는데..... 깊은 복사가 일어나니까... 엄청난 낭비가 될 것이다. 물론 최신 버전의 cpp에서는 RVO(Return Value Optimization) 라는게 있어서 실제 복사가 생략된다고는 한다. 그런데 경험해본 것처럼 대부분의 시스템은 레거시이니까... 조심해야겠다.
더 나아가서 포인터를 왜 사용하는지 알아보자.
MyClass* create() {
return new MyClass(); // 힙에 객체 생성
}
int main() {
MyClass* c = create(); // 포인터로 반환된 객체를 제어
delete c; // 메모리 해제 필요
}
이렇게 객체의 소멸자를 사용해서 메모리 해제가 되는듯하다. - 아직 배우지 않음 -
class Animal {
public:
virtual void speak() { std::cout << "Animal\n"; }
};
class Dog : public Animal {
public:
void speak() override { std::cout << "Dog\n"; }
};
Animal* createAnimal() {
return new Dog(); // 부모 타입 포인터로 자식 객체 참조
}