8.1 이번 장에서 만들어 볼 프로그램
8.2 포인터란?
int n = 10; // 변수 정의
int *p; // 포인터 선언
p = &n; // 변수 n의 주소를 포인터 p에 저장
#include <iostream>
using namespace std;
int main() {
int n = 10;
int* p = &n; // 포인터 p에 변수 n의 주소 저장
cout << p << endl; // 포인터 p의 값(주소) 출력
cout << *p << endl; // 포인터 p에 저장된 값 출력
return 0;
}
// nullptr
int *p = nullptr; // 포인터가 아무것도 가리키고 있지 않을 때 nullptr로 설정함
8.3 동적 메모리 할당(dynamic memory allocation)
: 프로그램이 실행 도중에 동적으로 메모리를 할당받는 것
new와 delete
: 동적 메모리는 new 연산자를 이용하여서 할당된다. new 뒤에는 자료형을 적는다. 만약 하나 이상의 요소가 필요하다면 [ ] 안에 요소의 숫자를 적는다. new 연산자는 할당되는 동적 메모리의 시작 주소를 반환한다.
int *p; // 포인터 선언
p = new int[5]; // 포인터에 동적 메모리의 시작 주소를 저장한다.
▶ 정적 배열 vs. 동적 배열
: 정적 배열은 컴파일 시에 크기가 결정되어야 한다.
반면에 동적 배열은 new에 의하여 생성되는데, 그 크기를 변경할 수 있다. 동적 배열은 컴퓨터 시스템에 의하여 히프 메모리 영역에서 할당된다.
컴퓨터 메모리는 한정된 자원이기 때문에 동적 메모리 할당 요청은 항상 만족되지 않는다. 요청한 메모리가 없는 경우에 bad_alloc이라는 오류(exception)가 발생한다.
동적 메모리는 사용이 끝나면 반드시 해제하여야 한다. 동적 메모리를 해제하려면 delete 키워드를 사용한다.
delete [] p;
#include <iostream>
#include <time.h>
using namespace std;
int main() {
int* p;
srand(time(NULL));
p = new int[10]; // 동적 메모리 할당
for (int i = 0; i < 10; i++)
p[i] = rand();
for (int i = 0; i < 10; i++)
cout << p[i] << " ";
cout << endl;
delete[] p; // 동적 메모리 반납
return 0;
}
8.4 스마트 포인터(smart pointer)
: 스마트 포인터를 사용하면 프로그래머가 동적 메모리 할당 후에 잊어버려도 자동으로 동적 메모리가 삭제된다.
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> p(new int); // 스마트 포인터
*p = 99; // p를 사용한다.
// p가 삭제되면서 동적 메모리도 함께 삭제하기 때문에 메모리 누수가 발생하지 않는다.
}
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int[]> p(new int[10]); // 정수형 배열을 가리키는 스마트 포인터
for (int i = 0; i < 10; i++)
p[i] = i; // 스마트 포인터 사용
for (int i = 0; i < 10; i++)
cout << p[i] << " ";
cout << endl;
return 0;
}
8.5 객체의 동적 생성
객체도 new와 delete를 사용하여 동적으로 생성할 수 있다.
어떤 경우에는 객체를 동적으로 생성하는 것이 객체 지향의 관점에서 바람직하다. 가끔은 객체가 몇 개나 생성되어야 하는지 알 수 없는 경우가 종종 있기 때문이다.
#include <iostream>
using namespace std;
class Dog {
public:
string name;
int age;
Dog(string s, int a) : name(s), age(a) {}
};
int main() {
Dog* pDog = new Dog("Puppy", 1); // 생성자 호출
delete pDog; // 소멸자 호출
return 0;
}
포인터를 통하여 멤버 접근하기
(*pDog).getAge(); 또는
pDog->getAge();
#include <iostream>
using namespace std;
class Dog {
public:
string name;
int age;
Dog(string n, int a) : name(n), age(a) {}
~Dog() {}
int getAge() {
return age;
}
void setAge(int dog_age) {
age = dog_age;
}
};
int main() {
Dog* pDog = new Dog("Puppy", 1);
cout << "강아지의 나이: " << pDog->getAge() << endl;
pDog->setAge(5);
cout << "강아지의 나이: " << pDog->getAge() << endl;
delete pDog;
return 0;
}
멤버도 동적 생성하기
: 클래스의 멤버도 히프에 동적 생성할 수 있다. 이럴 경우, 생성자에서 동적 할당되어야 하고, 소멸자에서 동적 메모리를 해제하여야 한다.
#include <iostream>
using namespace std;
class Dog {
public:
string* pName;
int* pAge;
Dog() {
pName = new string{ "Puppy" }; // 동적 객체 초기화
pAge = new int{ 1 };
}
~Dog() {
delete pName;
delete pAge;
}
int getAge() {
return *pAge;
}
void setAge(int dog_age) {
*pAge = dog_age;
}
};
int main() {
Dog* pDog = new Dog; // 동적 객체를 가리키는 포인터
cout << "강아지의 나이: " << pDog->getAge() << endl;
pDog->setAge(5);
cout << "강아지의 나이: " << pDog->getAge() << endl;
return 0;
}
this 포인터
: 함수를 호출하고 있는 객체를 알려주는 포인터
#include <iostream>
using namespace std;
class Rectangle {
public:
int width;
int height;
Rectangle() {
width = 30;
height = 40;
}
~Rectangle() {}
void setWidth(int w) {
this->width = w;
}
int getWidth() {
return this->width;
}
void setHeight(int h) {
this->height = h;
}
int getHeight() {
return this->height;
}
};
int main() {
Rectangle myRect;
cout << "사각형의 너비: " << myRect.getWidth() << endl;
cout << "사각형의 높이: " << myRect.getHeight() << endl;
myRect.setWidth(20);
myRect.setHeight(30);
cout << "사각형의 너비: " << myRect.getWidth() << endl;
cout << "사각형의 높이: " << myRect.getHeight() << endl;
return 0;
}
스마트 포인터(unique_ptr)를 이용한 동적 객체 생성
#include <iostream>
#include <memory>
using namespace std;
class Dog {
public:
string name;
int age;
Dog() {
name = "Puppy";
age = 1;
}
~Dog() {}
int getAge() {
return this->age;
}
void setAge(int dog_age) {
this->age = dog_age;
}
};
int main() {
std::unique_ptr<Dog> pDog(new Dog); // 스마트 포인터
cout << "강아지의 나이: " << pDog->getAge() << endl;
pDog->setAge(5);
cout << "강아지의 나이: " << pDog->getAge() << endl;
return 0;
}
8.6 const 포인터
객체 포인터를 언제 사용하는가?
'Programming > C++' 카테고리의 다른 글
[C++] 15. STL과 람다식 (1) | 2024.02.17 |
---|---|
[어서와 C++는 처음이지!] CH8 Exercise (1) | 2024.02.12 |
[어서와 C++는 처음이지!] CH6 Exercise (1) | 2024.01.30 |
[C++] 6. 객체 배열과 벡터 (1) | 2024.01.30 |
[어서와 C++는 처음이지!] CH5 Exercise (0) | 2024.01.29 |