pBuffer = new int[nLength];
객체가 넘어온다 = 주소값을 리턴한다!
힙 메모리에서 스택 메모리로 주소값을 넘겨준다.
int ar[100]; // 스택 메모리, 정적
new int[]; // 힙 메모리, 동적
delete pBuffer;
delete[] pBuffer;
MousePoint *pt;
pt = new MousePoint(10,20);
void main()
{
MousePoint *pt = new MousePoint(10, 20);
cout << pt->getX() << endl;
cout << pt->getY() << endl;
delete pt;
}
간접참조 ->는 C++에서만 쓴다. 다른 언어에서는 pt.getX()와 같은 직접참조 형식으로 사용한다.
MousePoint *pArr[3];
pArr[0] = new MousePoint(10,20);
pArr[1] = new MousePoint(100,200);
pArr[2] = new MousePoint(1000,2000);
new 연산자로 생성되는 모든 것들은 객체!
void main()
{
//MousePoint* pt1 = new MousePoint(10, 20);
//MousePoint* pt2 = new MousePoint(100, 200);
//MousePoint* pt3 = new MousePoint(1000, 2000);
MousePoint* pt[3];
pt[0] = new MousePoint(10, 20);
pt[1] = new MousePoint(100, 200);
pt[2] = new MousePoint(1000, 2000);
for (int i = 0; i < 3; i++)
{
cout << pt[i]->getX() << endl;
cout << pt[i]->getY() << endl;
}
for (int i = 0; i < 3; i++)
{
delete pt[i];
}
}
힙 메모리가 배열로 할당이 됐을 때는 delete에 배열표시를 붙여줘야 하고, delete[] pt
(배열이 오른쪽에서 할당)
pBuffer = new int[num];
힙 메모리 자체가 배열이 아닐 때는 배열 표시가 붙지 않고 배열의 요소를 써야한다. delete pt[i]
(왼쪽에서 할당받는 배열)
pt[0] = new MousePoint(10, 20);
자바, C#
String str = "Hello";
C, C++
char str[] = "Hello";
char* pStr = str;
자바와 C# 등에서는 Stirng이라는 타입(클래스)가 있지만, C와 C++에는 없어서 char를 사용한다.
#include<iostream>
using namespace std;
class String
{
private:
char* pBuffer;
int nLength;
public:
String(char ch, int size);
~String();
};
String::String(char ch, int nSize)
{
nLength = nSize;
pBuffer = new char[nLength + 1]; // 문자열은 끝에 \0 (null) 값이 붙으므로 + 1
memset(pBuffer, ch, nLength); // pBuffer에 ch를 nLength만큼 채우겠다.
pBuffer[nLength] = '\0';
cout << "pBuffer : " << pBuffer << endl;
cout << "nLength : " << nLength << endl;
}
String::~String()
{
delete pBuffer; // new로 동적 호출했으니 delete로 되돌린다.
}
void main()
{
String str('A', 3);
}
void* memset(void* ptr, int value, size_t num);
첫번째 인자 void* ptr : 세팅하고자 하는 메모리의 시작 주소
두번째 인자 value : 메모리에 세팅하고자 하는 값
세번째 인자 size_t : 길이
여기서 str2 = str1 하면 오류는 나지만 실행은 된다.
void main()
{
String str1('A', 3);
String str2('B', 5);
str2 = str1; //
}
스택 메모리에 의해 객체 str2가 먼저 삭제가 되고, str1이 삭제가 되는데 str2의 pBuffer가 삭제될 때, str2의 주소값이 str1의 주소값으로 대입되어 있기 때문에 str1의 주소값이 삭제가 된다.
따라서 이후 str1의 pBuffer가 삭제될 때 가리키고 있는 pBuffer는 존재하지 않아 오류가 나는 것이다.
⇒ delete 시도할 때 문제가 생김.
<대입 이전>
<대입 이후>
메모리 누수 문제가 발생한다.
str2.nLength = str1.nLength;
str2.pBuffer = str1.pBuffer;
nLength 멤버 변수끼리의 대입은 문제 없다.
pBuffer 멤버 변수는 포인터이기 때문에 문제가 발생한다.
기존에 있는 것을 delete 하고, 새로운 메모리를 생성해서 새로운 주소값을 받아온다!
void operator=(String& str1) // 대입 연산자 오버로딩 멤버함수
{
delete this->pBuffer;
this->nLength = str1.nLength;
this->pBuffer = new char[this->nLength + 1]; // 새로운 메모리를 할당해서 그 주소값을 pBuffer에 넘겨줌
strcpy(this->pBuffer, str1.pBuffer);
}
예제
#include<iostream>
#include<string.h>
using namespace std;
class String
{
private:
char* pBuffer;
int nLength;
public:
String(char ch, int size);
~String();
void operator=(String& str1); // 대입 연산자 오버로딩 멤버함수
void SetData();
};
String::String(char ch, int nSize)
{
nLength = nSize;
pBuffer = new char[nLength + 1]; // 문자열은 끝에 \0 (null) 값이 붙으므로 + 1
memset(pBuffer, ch, nLength); // pBuffer에 ch를 nLength만큼 채우겠다.
pBuffer[nLength] = '\0';
cout << "pBuffer : " << pBuffer << endl;
cout << "nLength : " << nLength << endl;
}
String::~String()
{
delete pBuffer; // new로 동적 호출했으니 delete로 되돌린다.
}
void String::operator=(String& str1) // 대입 연산자 오버로딩 멤버함수
{
delete this->pBuffer;
//this->nLength = str1.nLength;
this->pBuffer = new char[this->nLength + 1]; // 새로운 메모리를 할당해서 그 주소값을 pBuffer에 넘겨줌
strcpy_s(this->pBuffer, this->nLength + 1, str1.pBuffer);
}
void String::SetData()
{
cout << "pBuffer : " << this->pBuffer << endl;
cout << "nLength : " << this->nLength << endl;
}
void main()
{
String str1('A', 3);
String str2('B', 5);
//str2 = str1; // 에러
cout << "대입 전" << endl;
str2.SetData();
str2.operator=(str1); // 대입 연산자 오버로딩
// str2 = str1과 같은 문장
cout << "대입 후" << endl;
str2.SetData();
}
str2.operator=(str1);
와 str2 = str1
은 같은 기능을 하는 문장이다.
str1 = str1;
문제는 strcpy() 시에 s.pBuffer 값을 가져올 수 없으므로 복사 실패함.
새로운 메모리의 주소값을 만들어 넘겨 받는다.
하지만 값을 가져올 주소값을 잃었으므로 값을 가져올 수 없다. (원본이 사라짐)