Skip to content
This repository was archived by the owner on Oct 21, 2020. It is now read-only.

Latest commit

 

History

History
199 lines (149 loc) · 8.13 KB

File metadata and controls

199 lines (149 loc) · 8.13 KB

C++ 관련 질문

목차

Q. C++ VS Java

C++에서 가능한 기능

  • 힙에 할당하는 메모리를 직접 관리
  • 클래스
  • 객체
  • 생성자
  • 메서드 오버로딩/오버라이딩
  • 힙에 객체 생성하기
  • 스택에 객체 생성하기
  • 복사 생성자
  • 소멸자
  • 연산자 오버로딩
  • 정적 바인딩
  • 다중 상속
  • Call By Value 가능
  • Call By Reference 가능

Java에서 가능한 기능

  • 힙에 할당하는 메모리는 GC에서 자동 관리
  • 클래스
  • 객체
  • 생성자
  • 메서드 오버로딩/오버라이딩
  • 힙에 객체 생성하기
  • 동적 바인딩
  • 인터페이스
  • 인터페이스 다중 상속
  • Call By Value 가능
  • 초기값이 없으면 0으로 자동 초기화

Q. 클래스

접근 제어자(Access Modifier)

멤버 변수의 접근권한

C++에서 기본 접근권한은 private 입니다.

class vector
{
  int mX;  // private 멤버 변수
  int mY;  // private 멤버 변수
};

C++에서 접근 제어자는 아래와 같이 3가지로 구성되어 있습니다.

  • public: 누구나 접근 가능하다.
  • protected: 자식 클래스에서도 접근 가능하다.
  • private: 해당 클래스에서만 접근 가능하다.

C++에서는 보통 제어자 별로 멤버들을 그룹 지어서 선업합니다.

class SomeClass
{
public:
  int mPublicMember;
protected:
  int mProtectedMember;
private:
  int mPrivateMember1;
  int mPrivateMember2;
};

객체 생성

자바와 C++에서 개체를 생성하는 예제를 비교해보면 다음과 같습니다.

  • Java
// 스택 메모리에 생성할 수 없음

// 힙(heap) 메모리에 만들기 (느림)
Vector a = new Vector();
  • C++
// 스택(stack) 메모리에 만들기 (빠름)
Vector a;

// 힙(heap) 메모리에 만들기 (느림)
Vector* a = new Vector();

C++은 스택과 힙 메모리 영역 모두에서 객체를 생성할 수 있습니다. C++은 자바와 달리 모든 것을 스택 메모리 영역에 할당할 수 있습니다. 스택 영역은 힙과 달리 연속된 메모리를 찾는 과정을 거치지 않으므로 힙보다 빠른 성능을 갖습니다.(자바는 Primitive Type을 제외하고 모든 타입은 Reference Type이고 힙에 할당됩니다.)

C++에서 아래의 변수가 메모리에 어떤 상태인지 살펴봅시다.

Vector* b = new Vector();

CPP 05-1

위 그림은 스택과 힙 메모리 모습을 매우 간소화하여 나타낸 모습입니다. Vector 클래스의 포인터 변수인 b는 스택 메모리에 저장되며 주소 값을 갖습니다. 변수 bnew를 통해 동적할당을 하였으므로, 실제 데이터는 힙 메모리에 할당됩니다. 위 그림의 한 칸은 4byte이며, Vector 클래스의 멤버 변수는 2개의 int 자료형이므로 2칸을 차지하는 것을 볼 수 있습니다.

스택(Stack) 메모리

C++에서 스택 메모리 영역은 예약된 로컬 메모리 공간입니다. 스택 메모리 크기는 컴파일러 설정에서 변경할 수 있습니다. 일반적으로 1MB이하로 설정하며, 컴파일된 후 실행파일인 exe 파일의 스택 크기로 설정됩니다.

스택은 함수 호출과 반환, 정적인 변수와 객체를 저장하는 등의 역할을 합니다. 스택 메모리의 특징은 다음과 같습니다.

  • 단순히 스택 포인터를 옮긴다.
    • 함수를 호출하는 경우 해당 함수의 데이터를 스택 메모리에 할당한 후 스택 포인터를 함수의 시작지점으로 옮겨 수행을 시작합니다. 그리고 함수의 수행이 끝나면 이전 위치로 반환하여야 하는데, 이 때 사용이 끝난 메모리를 해제하는 것이 아니라 단순히 스택 포인터를 반환 지점으로 옮기고 다음 수행할 데이터로 덮어쓰는 형태로 동작합니다.
  • 크기가 작다.
    • 스택은 크기는 일반적으로 1MB 크기로 매우 작습니다. 따라서 스택 메모리 크기를 벗어난 데이터(객체)를 할당하려고 하면 stack overflow가 발생합니다.
  • 힙 메모리보다 빠르다.
    • 데이터를 할당할 때 연속된 크기를 찾는 작업이 필요없습니다.
    • 메모리 해제 작업이 필요없습니다.
    • 고정된 크기를 가지고 있으므로 컴파일러 단계에서 미리 스택 포인터의 행동반경을 설정할 수 있습니다.

힙(Heap) 메모리

힙 메모리는 프로그램이 실행하는 동안에 필요한 데이터를 할당하는 영역입니다. 힙 메모리 크기는 운영체제에서 관리하는 전체 메모리를 사용할 수 있어 크기가 큰 객체를 무리없이 저장할 수 있습니다. 하지만 해당 메모리에서 비어 있고 연속적인 공간을 찾아야 해서 느리며, C++과 같은 언매니지드 언어에서는 할당한 메모리를 직접 해제해주어야 합니다. 만약 해제하지 않으면 해당 공간은 어느 곳에서도 사용하지 못한 상태가 되어 메모리 누수가 발생합니다.

힙을 사용할 때 가장 주의할 점은 메모리 누수입니다. 이를 방지하기 위한 대표적인 패턴은 **RAII(Resource Acquisition Is Initialization)**입니다. 이는 자원을 할당한 경우에는 해당 자원의 영역(scope)가 끝나기 전에 해제해야 한다는 것입니다.이다.

Vector& PrintVectors(const Vector& a, const Vector& b)
{
  Vector* result = new Vector();
  result->mX = a.mX + b.mX;
  result->mY = a.mY + b.mY;

  return result;
}

위 코드는 매우 실수하기 쉬운 예입니다. result 변수는 힙 메모리에 할당되어 있는데, 이를 해제하지 해당 scope에서 해제하지 않고 반환하고 있습니다. 반환 받은 영역은 이를 해제해야 하는 책임까지 더해집니다. 위 메서드를 사용하는 클라이언트는 위 메서드를 확인하지 않으면 해제를 해야하는지도 모를 수 있습니다.

객체 배열(Object Array)

객체 배열을 생성하는데 있어서도 Java와 C++에는 차이가 존재합니다. 먼저 자바를 살펴봅시다.

// Java
Vector[] list = new Vector[10];

위 코드는 Vector 클래스를 10개 만들어 주는 것일까? Vector 클래스를 가리키는 4Byte 주소 공간을 10개 만들어주는 것일까?

정답은 4Byte 주소 공간을 10개만들어줍니다. 이 코드의 메모리 상태는 간단하게 아래와 같습니다.

CPP 05-2

힙 메모리에 10개의 주소 공간을 만들어주고 NULL을 삽입하여 초기화합니다. 그리고 각각의 Vector를 초기화하면 이가 할당된 힙 메모리 주소를 가리키게 될 것입니다.

그러면 C++을 보겠습니다.

// C++
Vector* list = new Vector[10];

C++은 위와 같이 선언하면 힙 메모리에 실제 10개의 Vector 클래스를 할당합니다.

CPP 05-3

힙 메모리 영역에 실제 Vector 클래스 10개가 할당된 모습입니다. Vector 클래스는 2개의 4Byte 정수 변수를 가지고 있으므로 각각 2칸씩 차지하는 모습입니다.

Java와 C++을 비교 정리하면 다음과 같습니다.

/* Java */
// 1) 힙에 백터 개체를 만들 수 없다.

// 2) 10개의 포인터를 힙에 만든다.
Vector[] a = new Vector[10];
/* C++ */
// 1) 10개의 백터 개체를 힙에 만든다.
Vector* list = new Vector[10];

// 2) 10개의 포인터를 힙에 만든다.
Vector** list = new Vector*[10];

객체 소멸

C++ 에서는 객체를 new와 같이 힙에 할당했으면 사용이 끝난 후에는 직접 해제를 해주어야 합니다.

Vector* a = new Vector();
Vector* list = new Vector[10];

// ...

delete a;       // 메로리가 즉시 해제된다.
a = NULL;       // 안해줘도 된다.

delete[] list;  // 배열을 소멸시키는 경우 []를 반드시 해주어야 한다.
list = NULL;    // 안해줘도 된다.

C++은 delete 키워드를 사용하여 메모리르 즉시 해제시켜줄 수 있습니다. 배열은 반드시 []를 선언해주어야 모든 배열을 해제합니다.