<aside> 💡 목차
</aside>
<aside> 💡 강의 일정표
<aside> 💡 [C++11] - 복사 생성자 vs 이동 생성자
[C++11] - 이동 대입 연산자 (operator=)
</aside>
<aside> 💡 Lock() 기반 스택이나 큐 작성할떄,
왜 굳이 복사생성자하고 이동대입 연산자는 왜 막은걸까?
//! lock 기반의 스택
template<typename T>
class LockStack
{
public:
LockStack(){};
~LockStack(){};
LockStack(const LockStack&) = delete; //! 복사 생성자는 삭제해버린다
LockStack& operator=(const LockStack&) = delete; //! 대입 연산자도 삭제해버린다
// -> (복사하려고해도, 응 돌아가~ 하는거임)
private:
stack<T> _stack;
mutex _mutex;
};
</aside>
<aside> 💡 복사 생성자와 이동 대입 연산자를 막은 주된 이유는 뮤텍스가 복사되는걸 막기 위해서임
이 클래스는 내부적으로 뮤텍스(mutex)를 사용하여 스레드 안전성을 보장하고 있습니다.
뮤텍스는 복사될 수 없는 자원이며, 복사될 경우 심각한 문제를 일으킬 수 있습니다.
뮤텍스 복사 문제: 만약
LockStack객체를 복사하게 되면, 내부의 뮤텍스도 같이 복사됩니다. 하지만 뮤텍스는 복사될 수 없는 자원입니다. 복사된 뮤텍스는 원본 뮤텍스와 독립적으로 동작하게 되어, 두 객체 간의 동기화가 깨지게 됩니다.LockStack<int> stack1; LockStack<int> stack2 = stack1; // 이렇게 하면 안 됩니다!
데이터 일관성 문제: 복사나 대입이 허용된다면, 한 객체의 상태가 변경될 때 다른 객체에 반영되지 않아 데이터 일관성 문제가 발생할 수 있습니다.
LockStack<int> stack1; stack1.push(10); LockStack<int> stack2 = stack1; // 복사가 허용된다고 가정 stack1.push(20); // 이 시점에서 stack1과 stack2의 내용이 다릅니다.
소유권 문제: 복사나 대입으로 인해 여러 객체가 같은 자원을 가리키게 되면, 자원 해제 시 문제가 발생할 수 있습니다.
LockStack<int*> stack1; stack1.push(new int(10)); LockStack<int*> stack2 = stack1; // 복사가 허용된다고 가정 // stack1과 stack2 중 어느 것이 메모리를 해제해야 할까요?
</aside>
<aside> 💡 그림으로 보면 다음과 같다
graph TD
A["LockStack 객체 1"]
B["LockStack 객체 2 (복사본)"]
C["스택 데이터"]
D["뮤텍스"]
E["스택 데이터 (복사됨)"]
F["뮤텍스 (복사 시도)"]
A -->|"포함"| C
A -->|"포함"| D
B -->|"포함"| E
B -->|"복사 시도"| F
style A fill:#0047AB,color:#FFFFFF
style B fill:#CC5500,color:#FFFFFF
style C fill:#006600,color:#FFFFFF
style D fill:#551A8B,color:#FFFFFF
style E fill:#006600,color:#FFFFFF
style F fill:#8B0000,color:#FFFFFF
</aside>
<aside> 💡 게임을 예시로 들어 복사 생성자와 이동 대입 연산자의 필요성을 알아보자
graph TD
A["게임 캐릭터"]
B["복사된 캐릭터"]
C["이동된 캐릭터"]
D["인벤토리"]
E["스킬"]
F["장비"]
A -->|"복사 생성자"| B
A -->|"이동 대입 연산자"| C
A --> D
A --> E
A --> F
style A fill:#0047AB,color:#FFFFFF
style B fill:#006600,color:#FFFFFF
style C fill:#CC5500,color:#FFFFFF
style D fill:#551A8B,color:#FFFFFF
style E fill:#404040,color:#FFFFFF
style F fill:#8B0000,color:#FFFFFF
**복사 생성자가 필요한 경우:**
- 캐릭터 복제: 게임에서 플레이어가 자신의 캐릭터를 복제하여 다른 서버나 게임 모드에서 사용하고 싶을 때, 복사 생성자가 필요합니다.
- 즉, 캐릭터 복제시 사용
class GameCharacter { private: std::vector<Item> inventory; std::vector<Skill> skills; Equipment equipment; public: GameCharacter(const GameCharacter& other) : inventory(other.inventory), skills(other.skills), equipment(other.equipment) { // 캐릭터의 모든 상태를 정확히 복사 } }; // 사용 예 GameCharacter originalChar; GameCharacter clonedChar = originalChar; // 복사 생성자 호출
**이동 대입 연산자가 필요한 경우:**
- 캐릭터 이전: 한 계정에서 다른 계정으로 캐릭터를 이전할 때, 이동 대입 연산자를 사용하면 효율적입니다.
- 즉, 캐릭터 계정 이동시 사용!
class GameCharacter { public: GameCharacter& operator=(GameCharacter&& other) noexcept { if (this != &other) { inventory = std::move(other.inventory); skills = std::move(other.skills); equipment = std::move(other.equipment); other.resetCharacter(); // 원본 캐릭터 초기화 } return *this; } private: void resetCharacter() { // 캐릭터 상태 초기화 } }; // 사용 예 GameCharacter oldAccount; GameCharacter newAccount; newAccount = std::move(oldAccount); // 이동 대입 연산자 호출