๋ฌธ์ ๊ฐ ๋๋ ์ฝ๋
class Cat
{
public:
Cat() { mAge = 1; }
Cat(int age) { mAge = age; }
private:
int mAge;
};
class Zoo
{
public:
Zoo(int kittyAge) { mKitty = Cat(kittyAge); } // โ ๋นํจ์จ์ !
private:
Cat mKitty;
};
int main()
{
Zoo cppZoo(4);
return 0;
}
๋ฌธ์ ์ : ๋ถํ์ํ ์์ ๊ฐ์ฒด ์์ฑ
1. Zoo ์์ฑ์๊ฐ ์คํ๋๊ธฐ ์ ์ mKitty์ ๊ธฐ๋ณธ ์์ฑ์ Cat()๊ฐ ๋จผ์ ํธ์ถ๋จ
2. ์์ฑ์ ๋ณธ๋ฌธ์์ Cat(kittyAge)๋ก ์์ ๊ฐ์ฒด๋ฅผ ์์ฑ
3. ์์ ๊ฐ์ฒด๋ฅผ mKitty์ ๋์
(๋ณต์ฌ ๋๋ ์ด๋)
4. ์์ ๊ฐ์ฒด ์๋ฉธ
โ ์ด 2๋ฒ์ ์์ฑ์ ํธ์ถ + 1๋ฒ์ ๋์ ์ฐ์ฐ ๋ฐ์
Member Initializer List๋ก ํด๊ฒฐ
class Zoo
{
public:
Zoo(int kittyAge) : mKitty{kittyAge} {} // โ
ํจ์จ์ !
private:
Cat mKitty;
};
์ฅ์ :
mKitty๋ฅผ ์์ฑ๊ณผ ๋์์ ์ด๊ธฐํMember Initializer List ์ฌ์ฉ ๊ท์น
() ๋์ {}๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ์์ (narrowing conversion ๋ฐฉ์ง)const ๋ฉค๋ฒ ๋ณ์์ ์ฐธ์กฐ ๋ฉค๋ฒ ๋ณ์๋ ๋ฐ๋์ ์ด๊ธฐํ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํด์ผ ํจclass Example
{
public:
Example(int a, int b, int c)
: mA{a} // ๋ฉค๋ฒ ๋ณ์
, mB{b} // ์ฝค๋ง๋ก ๊ตฌ๋ถ
, mC{c} {} // ๋ง์ง๋ง๋ ์ฝค๋ง ๊ฐ๋ฅ
private:
int mA;
int mB;
int mC;
};
๊ธฐ๋ณธ ์์ ์ฝ๋
class Cat
{
public:
Cat() = default; // ๊ธฐ๋ณธ ์์ฑ์๋ ์ปดํ์ผ๋ฌ๊ฐ ์๋ ์์ฑ
Cat(std::string name, int age)
: mName{std::move(name)}
, mAge{age}
{
std::cout << mName << " constructor" << std::endl;
}
~Cat()
{
std::cout << mName << " destructor" << std::endl;
}
// Copy Constructor (๋ณต์ฌ ์์ฑ์)
Cat(const Cat& other)
: mName{other.mName}
, mAge{other.mAge}
{
std::cout << mName << " copy constructor" << std::endl;
}
// Move Constructor (์ด๋ ์์ฑ์)
Cat(Cat&& other) noexcept
: mName{std::move(other.mName)}
, mAge{other.mAge}
{
std::cout << mName << " move constructor" << std::endl;
}
// Copy Assignment (๋ณต์ฌ ๋์
์ฐ์ฐ์)
Cat& operator=(const Cat& other)
{
if (&other == this) return *this; // Self-assignment ์ฒดํฌ
mName = other.mName;
mAge = other.mAge;
std::cout << mName << " copy assignment" << std::endl;
return *this;
}
// Move Assignment (์ด๋ ๋์
์ฐ์ฐ์)
Cat& operator=(Cat&& other) noexcept
{
if (&other == this) return *this; // Self-assignment ์ฒดํฌ
mName = std::move(other.mName);
mAge = other.mAge;
std::cout << mName << " move assignment" << std::endl;
return *this;
}
void print() const
{
std::cout << mName << " " << mAge << std::endl;
}
private:
std::string mName;
int mAge;
};
์ฌ์ฉ ์์
int main()
{
Cat kitty{"kitty", 1}; // ์ผ๋ฐ ์์ฑ์
Cat kitty2{kitty}; // ๋ณต์ฌ ์์ฑ์
Cat kitty3{std::move(kitty)}; // ์ด๋ ์์ฑ์
Cat bori{"bori", 1};
Cat nabi{"nabi", 2};
//bori = nabi; // ๋ณต์ฌ ๋์
์ฐ์ฐ์
bori = std::move(nabi); // ์ด๋ ๋์
์ฐ์ฐ์
bori.print(); // nabi 2 (nabi์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ด)
nabi.print(); // (empty) 2 (mName์ด ์ด๋๋์ด ๋น์ด์์)
return 0;
}


Self-Assignment๋?
Cat kitty{"kitty", 1};
kitty = kitty; // ์๊ธฐ ์์ ์ ๋์
kitty = std::move(kitty); // ์๊ธฐ ์์ ์ ์ด๋
๋ฌธ์ ์ํฉ
int, string ๋ฑ) ๋ฉค๋ฒ๋ง ์์ผ๋ฉด ํฐ ๋ฌธ์ ์์class Cat
{
std::string* mName; // ํฌ์ธํฐ ๋ฉค๋ฒ
public:
Cat& operator=(const Cat& other)
{
delete mName; // 1. ์์ ์ ๋ฉ๋ชจ๋ฆฌ ํด์
mName = new std::string(*other.mName); // 2. other๋ ๊ฐ์ ๊ฐ์ฒด๋ฉด?
// โ ์ด๋ฏธ ํด์ ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ์ผ๋ ค๊ณ ์๋! (Undefined Behavior)
return *this;
}
};
ํด๊ฒฐ ๋ฐฉ๋ฒ: Self-Assignment ์ฒดํฌ
Cat& operator=(const Cat& other)
{
if (&other == this) return *this; // โ
์๊ธฐ ์์ ์ด๋ฉด ๋ฐ๋ก ๋ฆฌํด
mName = other.mName;
mAge = other.mAge;
std::cout << mName << " copy assignment" << std::endl;
return *this;
}
Cat& operator=(Cat&& other) noexcept
{
if (&other == this) return *this; // โ
์ด๋์์๋ ์ฒดํฌ ํ์
mName = std::move(other.mName);
mAge = other.mAge;
std::cout << mName << " move assignment" << std::endl;
return *this;
}
noexcept๋ฅผ ๋ถ์ฌ์ผ ํ๋ ํจ์
1. Destructor (์๋ฉธ์)
2. Move Constructor (์ด๋ ์์ฑ์)
3. Move Assignment (์ด๋ ๋์
์ฐ์ฐ์)
์ด์ :
noexcept๋ฅผ ๋ช
์ํ๋ฉด ์ปดํ์ผ๋ฌ๊ฐ ๋ ํจ์จ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์~Cat() noexcept {} // ์๋ฉธ์๋ ์๋ฌต์ ์ผ๋ก noexcept์ด์ง๋ง ๋ช
์ ๊ฐ๋ฅ
Cat(Cat&& other) noexcept
: mName{std::move(other.mName)}
, mAge{other.mAge} {}
Cat& operator=(Cat&& other) noexcept
{
if (&other == this) return *this;
mName = std::move(other.mName);
mAge = other.mAge;
return *this;
}
noexcept์ ์ค์์ฑ
std::vector<Cat> cats;
cats.push_back(Cat{"kitty", 1});
// vector๊ฐ ํฌ๊ธฐ๋ฅผ ๋๋ฆด ๋:
// - Move constructor๊ฐ noexcept๋ฉด โ ์ด๋ ์ฌ์ฉ (๋น ๋ฆ)
// - noexcept๊ฐ ์์ผ๋ฉด โ ๋ณต์ฌ ์ฌ์ฉ (๋๋ฆผ, ์์ ํจ)
ํจ์ ์ฌ์ฉ ๊ธ์ง: = delete
class Cat
{
public:
Cat(const Cat& other) = delete; // ๋ณต์ฌ ์์ฑ์ ์ฌ์ฉ ๊ธ์ง
Cat& operator=(const Cat& other) = delete; // ๋ณต์ฌ ๋์
์ฌ์ฉ ๊ธ์ง
};
int main()
{
Cat kitty{"kitty", 1};
Cat kitty2{kitty}; // โ ์ปดํ์ผ ์๋ฌ!
return 0;
}
์ฌ์ฉ ์ฌ๋ก:
C++11 ์ด์ ๋ฐฉ์
class Cat
{
private:
Cat(const Cat& other); // ์ ์ธ๋ง ํ๊ณ ๊ตฌํํ์ง ์์
Cat& operator=(const Cat& other);
// private์ด๋ฏ๋ก ์ธ๋ถ์์ ํธ์ถ ๋ถ๊ฐ
// ๊ตฌํ์ด ์์ผ๋ฏ๋ก ํด๋์ค ๋ด๋ถ์์๋ ๋งํฌ ์๋ฌ ๋ฐ์
};
Rule of Zero/Three/Five
์ฝ๋์๋ ํ๋ก๊ทธ๋๋ฐ
C++ Constructors and Destructors