-> 암시적 복사 생성자로 인해 pA가 가리키는 곳과 B가 가리키는 곳의 메모리가 동일해진다.
delete pA로 지우면 동일한 메모리를 가리키는 B의 참조값이 null값이 되어
문제가 발생하는데
이를 얕은 복사라고 한다.
이러한 문제를 해결하기 위해 개발자는 명시적으로 복사 생성자를 만들어줘야 한다.
: CObject a(b), CObject a = b; 를 통해 복사 생성자의 호출은
이런식으로 2번의 경우에 발생한다는 것을 확인했다.
하지만 또 다른 하나가 있다.
바로바로!! 객체의 값에 의한 호출이다.
void func(CObject a)
{
}
-> 디폴트 생성자도 아닌 복사 생성자가 호출된다.
그로 인해 함수가 종료될때 지역값이므로 소멸자도 호출된다.
비용이 크므로 객체를 매개변수로 보낼때는 레퍼런스를 사용하도록 권장한다.
아니 반드시 레퍼런스타입으로 매개변수를 사용해야 한다.
매개변수로 객체를 value값으로 사용할때
레퍼런스타입으로 보내자.
-> 불필요한 객체 생성을 차단했다.
=> 추가적으로 매개변수로 들어오는 값 변경을 막기위해 const도 붙이자!
: 바로 함수내의 객체를 반환하는 경우, 복사 생성자가 호출된다.
생각해보면 이미 사라질 객체를 반환하면 복사 생성자로 인해 다른 객체의 메모리가 생성이 되는데, 사라질 객체의 메모리를 delete 하는 부분을 차단하고,
그 객체를 받아와 쓴다면 오히려 메모리를 아낄 수 있다.
뭔소리고?? 어떻게 하냐면? rValue 참조를 사용하면 된다.
복사 생성자로 메모리가 두번 생성하는 코드
Rvalue reference를 통해 메모리 재활용하는 코드
: rValue 참조를 이용해 메모리 할당이 한번만 발생했다.
#include <iostream>
using namespace std;
class CText
{
public :
CText(const char *Text)
{
cout << "constructor " << endl;
mLen = strlen(Text);
mText = new char[mLen + 1];
strcpy(mText, Text);
}
CText(const CText& obj)
{
cout << "copy constructor " << endl;
mText = new char[obj.mLen + 1];
cout << "memory allocation " << endl;
strcpy(mText, obj.mText);
mLen = obj.mLen;
}
CText(CText&& obj)
{
cout << "move constructor " << endl;
mText = obj.mText;
mLen = obj.mLen;
obj.mText = nullptr;
obj.mLen = 0;
}
~CText() {
cout << " destructor " << endl;
if (mText)
{
cout << "memory delete " << endl;
delete[] mText;
mLen = 0;
}
}
char *mText;
int mLen;
};
CText GetText()
{
CText temp("hi world");
return temp;
}
int main()
{
CText t1 = GetText();
}
임시객체를 반환한다면, 복사 생성으로 메모리 하나 생성이 되는 것을
방지하기 위해 rValue 참조를 사용하자!
: 기본타입형에서 같다 다르다는 메모리의 크기나 비트 상태를 비교하는 것이 아니다. 값을 비교하는 것이다.
: double과 int의 메모리 구조가 다르지만, 값이 같으므로 같다라는 출력이 나오는 것을 확인할 수 있다.
: 왜냐하면 대입연산자를 여러개 정의할 수 있기 때문이다.