티스토리 뷰
개체 생성
class Vector
{
};
스택
Vector a; // 스택 메모리에 만들기
- 스택
- 예약된 로컬 메모리 공간 (작다, 일반적으로 1MB 이하)
- 함수 호출과 반환이 이 메모리에서 일어남
- 단순히 스택 포인터를 옮기는 것
- 메모리를 할당 및 해제할 필요 없음
- 스택에 할당된 메모리는 범위(scope)를 벗어나면 사라짐
- 변수와 매개변수를 위해, 필요한 크기는 컴파일 도중에 알 수 있음
- 하지만 스택에 큰 개체를 많이 넣으면
- 스택 오버플로우(overflow)가 발생할 수 있음
- 👁️ 성능이 느려질 수도 있음
- OS 에서 메모리 정책을 생각해보자
- 당장 쓰지 않는 부분은 swap file 로 남겨둠
- file 페이징, 메모리 페이징 처리
- 즉, 필요할때 갖고오는 것
- 당장 쓰지 않는 부분은 swap file 로 남겨둠
- 따라서, 필요한 시점에 메모리에 load될때 느려질 수 있음
- OS 에서 메모리 정책을 생각해보자
힙
Vector* b = new Vector(); // 힙 메모리에 만들기
- 힙
- 전역 메모리 공간 (큼, ~GBs)
- 비어있고 연속된 메모리 블록을 찾아야함
- 프로그래머가 메모리를 직접 할당 및 해제해야함
- 그렇지 않으면, 메모리 누수 발생
힙 vs 스택
- 스택을 쓸 수 있으면 무조건 스택을 쓰는게 좋다.
- 힙을 써야하는 경우는
- 한 함수 스코프 안에서 안끝나고, 여기저기 패스해야하는 경우
- 함수에서 반환값으로 오브젝트를 그대로 반환하면 그 값이 복사되면서 호출자한테까지 전달되는데 그 오브젝트가 너무 크다. 그런 경우 차라리 힙에 오브젝트를 만들고 주소 하나를 반환하는게 빠름 (메모리 복사 많이 하는 것보다 빠르다 - 이 경우 오브젝트 크기하고 상관이 있음을 알 수 있음)
개체 배열(array)
Vector* list = new Vector[10];
Quiz. 무엇을 만들까? Vector의 포인터 vs Vector ?
A. 진짜 Vector 를 만든다
- 생성자로 값을 채운 실제 개체가 잡힌다
- 기억해두자
- new Vector[10]; 에서 포인터 표시가 없음
한번에 보기
// 10개의 벡터 개체를 힙에 만듦
Vector* list = new Vector[10];
// 10개의 (벡터 개체의)포인터를 힙에 만듦
Vector** list = new Vector*[10];
개체 소멸
Vector* a = new Vector;
Vector* list = new Vector[10];
// ...
delete a; // 메모리가 즉시 해제됨
delete[] list; // [] 를 반드시 넣어야함
🔥 메모리 누수 방지
- new 를 사용했다면 꼭 delete 하자
- 안한다면, 프로그램 종료까지 메모리를 다른곳에서 쓸수가 없다 ㅜㅜ
멤버 변수 초기화
class Vector
{
private:
int mX;
int mY;
};
Vector a;
Vector* b = new Vector();
스택이나 힙 어디에 생기던,
- 값이 초기화 되지 않음
- 전에 메모리 공간에 저장되어있던 값을 사용함
- Java 등에서 초기화되는건, 안전은 하겠지만, 성능을 희생하는 것임
만약, 0으로 초기화한다면… (C 의사코드)
Vector a = new Vector();
// C 의사코드
void* ptr = malloc(sizeof(Vector));
memset(ptr, 0, sizeof(Vector)); // 👈
a = (Vector*)ptr;
new / delete vs malloc() / free()
내 생각 정리
- malloc() / free()
- 전통적인, 힙메모리 할당기 이다
- malloc 으로 원하는 크기를 할당해오고, 그 주소를 반환받는다
- 할당해온 메모리의 주소를 free 로 반환한다
- 개체를 생각하지 말고, 딱 함수의 개념으로 이해하자
- new / delete
- 개체의 생성과 소멸에 관여되는 키워드, 언어차원에서 개체 관리를 위해 지원
- 생성자/소멸자를 호출하여 그 로직을 실행시키는 추가 기능(개체 관리)이 있다고 크게 정리하면 어떨까? ㅎㅎ
초기화 리스트(Initializer List)
초기화 리스트
class Vector
{
public:
Vector()
: mX(0)
, mY(0)
{
}
private:
int mX;
int mY;
};
- 개체 생성 시, 초기화 되는 것임. 대입이 아님
- const, 레퍼런스(참조) 변수를 초기화 가능하다
참고로, 대입
class Vector
{
public:
Vector()
{
mX = 0;
mY = 0;
}
private:
int mX;
int mY;
};
헤더파일과 cpp파일 분리해서 작성
- 헤더파일
class Vector
{
public:
Vector();
Vector(int x, int y);
private:
int mX;
int mY;
};
- cpp파일
Vector::Vector()
: mX(0)
, mY(0)
{
}
Vector::Vector(int x, int y)
: mX(0)
, mY(0)
{
}
컴파일러와 생성자
기본 생성자
- 기본 생성자는 매개변수를 받지 않음
- 클래스에 생성자가 없으면 컴파일러가 기본 생성자를 자동적으로 만들어줌
- 이렇게 자동적으로 만들어진 생성자는, 멤버 변수를 초기화하지 않음
- 구현체 코드가 아래와 같이 생성됨
Vector::Vector()
{
}
컴파일러와 생성자
- 클래스에서 생성자가 없다면
- 기본 생성자를 만들어줌
- 클래스에서 생성자가 있다면
- 아무 작업 하지 않음 (기본생성자를 만들어주지 않음)
생성자 오버로딩(overloading)
- 여러개의 생성자를 만들 수 있음
- 같은 이름
- 인자의 개수나 자료형은 다름
매개변수 목록이 일치하는 생성자를 호출한다.
- 기본 생성자 예시
Vector() : mX(0), mY(0) {}
// 기본 생성자 호출
Vector a;
Vector a();
- 매개 변수를 가지는 생성자 예시
Vector(int x, int y)
: mX(x)
, mY(y)
{
}
Vector a(1, 3);
생성자 (Constructor)
언제 호출될까? (생성할때)
- 스택에 생성할때
- 힙에 생성할때 (new)
소멸자 (Destructor)
언제 호출될까? (지워질때)
- 스택 범위가 지워질때
- new 로 만든 개체를 delete로 지울때
// vector.h
class Vector
{
public:
~Vector(); // 소멸자
private:
int mX;
int mY;
};
// vector.cpp
Vector::~Vector()
{
}
소멸자
- 개체가 지워질 때 호출됨
- 가상 소멸자(동적 바인딩)
- C++ 는 언매니지드 언어
- 👁️ C++ 클래스는 그 안에서 동적으로 메모리를 할당할 수도 있음
- 그런 경우 필히 소멸자에서 메모리를 직접 해제해 줘야한다
클래스 안에서의 동적 메모리 할당하는 경우 (소멸자에서 메모리 직접 해제 필요)
// MyString.h
class MyString
{
public:
MyString();
private:
char* mChars;
int mLength;
int mCapacity;
};
// MyString.cpp
MyString::MyString()
: mLength(0)
, mCapacity(15)
{
mChars = new char[mCapacity + 1]; // 클래스 안에서의 동적 메모리 할당
}
- 🔥 메모리 해제 !!!!
// MyString.h
class MyString
{
public:
MyString();
~MyString();
private:
char* mChars;
int mLength;
int mCapacity;
};
// MyString.cpp
MyString::MyString()
: mLength(0)
, mCapacity(15)
{
mChars = new char[mCapacity + 1]; // 클래스 안에서의 동적 메모리 할당
}
MyString::~MyString()
{
delete[] mChars;
// mCapacity = 0;
// mChars = NULL;
}
Const 멤버함수
// vector.h
class Vector
{
public:
void SetX(int x);
void SetY(int y);
int GetX() const; // 👈
int GetY() const; // 👈
void Add(const Vector& other);
private:
int mX;
int mY;
};
- const 메서드 : 해당 개체 안의 어떠한 것도 바꾸지 않음
void Add(const Vector& other) const
{
mX = mX + other.mX; // 컴파일 에러
mY = mY + other.mY; // 컴파일 에러
}
- 🔥 🤙 기본적으로는 const 함수로 작성하자
- 제한적으로 작성하다가, 정말 필요하면 제거하자
구조체(struct) vs 클래스(class) in C++
기본 접근 권한
struct Vector
{
int X;
int Y;
};
class Vector
{
int mX;
int mY;
};
- struct
- public
- class
- private
struct Vector
{
int X; // public 멤버변수
int Y; // public 멤버변수
};
class Vector
{
int mX; // private 멤버변수
int mY; // private 멤버변수
}; // 안좋은 코딩 스타일. private: 를 명시해주자
🔥 Q. 컴퓨터는 이 둘을 구분할까?
A. 당연하게도 아니요. 컴퓨터는 모름. 단지 언어(컴파일러)단에서 구현한 개념임.
구조체에 관한 코딩표준
- C++에서는 구조체를 클래스처럼 쓸 수 있다
- 하지만 절대 그러지 말 것
- 🔥 구조체는 C 스타일로 쓰자
- 🔥 struct 는 순수하게 데이터뿐이여야함 (Plain Old Data, POD)
- 사용자가 선언한 생성자나 소멸자 X
- static 아닌 private/protected 멤버 변수 X
- 가상 함수 X
- 메모리 카피가 가능함
- memcpy() 를 사용하여 struct를 char[]로, 혹은 반대로 복사할 수 있음
- 👁️ 까탈스럽게 가면, 인디렉션 자체를 하지않도록 하자(파일 저장 가능하게)
'C・C++ > OOP' 카테고리의 다른 글
[C++] low level 개체지향 프로그래밍 3 (1) | 2024.10.06 |
---|---|
[C++] low level 개체지향 프로그래밍 2 (1) | 2024.10.06 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- sleep lock
- Dispatcher Servlet
- Java
- S4
- pocu
- tree
- C
- 연관관계 편의 메서드
- 논문추천
- reader-writer lock
- generic swap
- servlet
- tomcat11
- generic sort
- 톰캣11
- CPU
- 백준
- OOP
- 개발 공부 자료
- Spring MVC
- Memory
- thread
- core c++
- 이진탐색
- 객체 변조 방어
- 엔티티 설계 주의점
- S1
- condition variable
- PS
- JPA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함