#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Cat
{
private:
char* mName = nullptr;
int mAge;
public:
Cat() = default;
Cat(const char* name, int age) : mAge{ age }
{
int ssize = sizeof(name);
mName = new char[sizeof(name) +1];
memcpy(mName, name, ssize);
cout << mName << "constructor" << endl;
}
~Cat()
{
static int n = 0;
++n;
if (mName != nullptr)
{
cout << mName << "destructor" << endl;
delete mName;
}
else
{
cout << "이미 해지됨 ! " << endl;
}
}
//복사 생성자.
Cat(const Cat& other) : mAge{ other.mAge }
{
int ssize = sizeof(other.mName);
mName = new char[sizeof(other.mName) + 1];
memcpy(mName, other.mName, ssize);
cout << mName << "Copy 생성자 " << endl;
}
//Cat(const Cat& other) = default;
//Cat(Cat&& other) = default;
//이동 생성자.
Cat(Cat&& other) noexcept
: mName{ move(other.mName) }, mAge{ other.mAge }
{
other.mName = 0;
cout << mName << "이동 생성자 " << endl;
}
void print()
{
if (mName != nullptr)
cout << mName << " " << mAge << endl;
else
cout << "이미 nullptr" << endl;
}
};
int main()
{
Cat kitty{ "키티", 1 };
Cat kitty2{ kitty };
Cat kitty3 = move(kitty);
kitty.print();
kitty2.print();
kitty3.print();
return 0;
}
결과
: 이 때는 복사 생성자와 이동 생성자를 유저가 잘 만들었기 때문에
메모리 릭 발생하지 않음.
프로젝트 코드 중에 이동생성자랑 복사 생성자에 default 처리된 것이 있어서 궁금했다.
: 힙 멤버가 있는데 이 때도 가능할지??
-> 당연하게도 힙메모리 접근 오류 발생한다.
: 유저가 직접 동적할당하는 new 의 경우에 얕은 복사를 방지하기 위해서이다.
vector, string, 스마트 포인트는 무관한다.
1) 생성자
2) 소멸자
3) copy / move 생성자
4) copy / move 대입 연산자
https://blog.naver.com/kimwontae466/222388846175
https://modoocode.com/286
1) 변환 생성자의 매개변수를 초기화하자.
2) 유저가 디폴트 생성자를 만든다.
3) 디폴트를 명시시킴으로, 컴파일러 생성자를 호출하도록 한다.
: 기존 오브젝트를 복사해 새로운 오브젝트를 만들때 사용하는 생성자.
-> kitty3 = kitty는 equal로 인해 대입이 사용되었다 라고 생각하겠지만,
실제로는 새로운 오브젝트가 생성이 되는 과정이어서 복사 생성자가 호출된다.
=> 추가적으로 이러한 모호성, 즉 복사생성인지, 복사 대입인지 애매하므로,
{}를 이용해서 오브젝트를 생성하는 것을 권장한다.
: 기존 객체의 주소 및 value값을 새로운 오브젝트에 소유권을 이전하게 하는 생성자로, 기존 객체의 값이 이전된다.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Cat
{
private :
string mName;
int mAge;
public :
Cat() = default;
Cat(string name , int age ) : mName{ move(name) }, mAge{age}
{
cout << mName << "constructor" << endl;
}
~Cat()
{
cout << mName << "destructor" << endl;
}
//복사 생성자.
Cat(const Cat& other) : mName{ other.mName }, mAge{ other.mAge }
{
cout << mName << "Copy 생성자 " << endl;
}
//이동 생성자.
Cat(Cat && other) :mName{ move(other.mName) }, mAge{ other.mAge }
{
cout << mName << "이동 생성자 " << endl;
}
void print()
{
cout << mName << " " << mAge << endl;
}
};
int main()
{
Cat kitty{"키티", 1};
Cat kitty2{ kitty };
Cat kitty3 = kitty ;
return 0;
}
-> 여기서 우리는 포인터가 아닌 string을 사용중이므로 move를 통해 소유권을 이전시킬 수 잇다.
=> 이동생성자를 호출하기 위해서는 호출 부에서 rValue를 넣어줘야 하므로
move를 이용해 호출하도록 하자.
만약에 mPtr이라는 포인터가 있을 경우에는
복사 생성자에서는 memcpy를 통해 메모리를 복사하자.
: 한글의 경우, 2바이트 이기 때문에 대입을 통해서는 불가하다.
이동생성자에서는 유저가 대입해서 얕은 복사로 옮기고, 포인터를 nullptr로
만듦으로써 소유권을 이전시키자.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Cat
{
private :
string mName;
int mAge;
public :
Cat() = default;
Cat(string name , int age ) : mName{ move(name) }, mAge{age}
{
cout << mName << "constructor" << endl;
}
~Cat()
{
cout << mName << "destructor" << endl;
}
//복사 생성자.
Cat(const Cat& other) : mName{ other.mName }, mAge{ other.mAge }
{
cout << mName << "Copy 생성자 " << endl;
}
//이동 생성자.
Cat(Cat && other) :mName{ move(other.mName) }, mAge{ other.mAge }
{
cout << mName << "이동 생성자 " << endl;
}
void print()
{
cout << mName << " " << mAge << endl;
}
};
int main()
{
Cat kitty{"키티", 1};
Cat kitty2{ kitty };
Cat kitty3{ move(kitty) };
return 0;
}