Effective C++/Chapter 2: 생성자, 소멸자 및 대입 연산자 8

[Effective C++] 항목 12: 객체의 모든 부분을 빠짐없이 복사하자

1. 개요설계가 잘 된 클래스를 보면 객체를 복사하는 함수는 딱 2개 있습니다. 1. 복사 생성자2. 복사 대입 연산자 우리는 이 둘을 통틀어서 복사 함수라고 부릅니다. 우리는 컴파일러가 자동으로 생성해주는 복사 함수 이외에 개발자가 따로 선언하는 것도 가능합니다. 그러나 컴파일러는 우리가 복사 함수를 잘못 선언해도 알려주지 않습니다. 그 예시를 한번 보도록 하죠 2. 복사 함수에 문제가 생길 때void logCall(const std::string& funcName); // make a log entryclass Customer {public: Customer(const Customer& rhs); Customer& operator=(const Customer& rhs);private: ..

[Effective C++] 항목 11: operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자

1. 개요자기대입은 어떤 객체가 자기 자신에게 대입 연산을 실행하는 것을 말합니다. 예를 들면 이런것이죠 Yeoul y; y=y; 문법상 아무 문제가 없는 코드입니다. a[i] = a[j]; i와j가 같아지면 자기대입이 됩니다. *pa = *pb; 둘이 가리키는 대상이 같으면 자기대입이 됩니다. 이러한 경우가 생기는 이유는 하나의 객체를 여러곳에서 참조하는 중복참조 상태 때문입니다. 이럴땐 같은 객체가 사용될 가능성을 고려하는것이 바람직한 자세입니다. void DoSomething(const Base& rb, Derived* pd);// 사실 rb와 *pb는 같은 객체였을지도 모릅니다. 결론은 자기 대입 연산은 생각보다 빈번하게 발생할 수 있다는 것이지요 2. 발생하는 문제들/해결법 2-1. 문제1자기대..

[Effective C++] 항목 10: 대입 연산자는 *this의 참조자를 반환하게 하자

1. 개요C++의 대입 연산자는 여러개가 동시에 엮일 수 있습니다. 무슨말인가 하면 우리는 일반적으로 대입연산자를 a=3; 이런식으로 씁니다. 그러나 a=b=c=3; 이런식으로 쓰는것도 가능하다는 말입니다. 우측 부터 연산이 진행되는 연산자입니다. 위의 연산을 괄호를 쳐서 본다면 이렇게 됩니다. a=(b=(c=3)); c에 3대입되고 그 결과가 b에 대입되고 다시 그 결과가 a에 대입됩니다. 이러한 연산이 가능하려면 연산자가 좌변에 대한 참조자를 반환하도록 구현되어 있어야 합니다.2. 다른것들은?좌변 객체의 참조자를 반환하자는 규칙은 = 뿐만 아니라 다른 경우에도 지켜져야 합니다. 예를들면 += -= *= 등과같은 연산고 *this를 반환하게 하는것이 관례입니다. 이 관례는 모든 기본제공 타입들이 따..

[Effective C++] 항목 9: 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자

1. 개요저자는 객체 생성, 소멸중에 가상 함수를 절대 호출하지 말라고 합니다. 그 이유는 무엇일까? 지금부터 알아 보도록 합시다. 2. 문제아래 코드를 보면 Transaction이 가장 최상위 클래스이고 하위로 BuyTransaction, SellTransaction이 각각 Transaction을 상속받고 있는 상태입니다. main에서는 BuyTransaciton의 객체를 만들어 주고 있습니다. BuyTransaction객체를 만들기 위해서는 부모 클래스의 생성자가 먼저 호출되야 합니다. 그렇게 부모클래스인 Transaction의 생성자가 호출되는데 여기서 문제가 발생합니다. 왜냐하면 Transaction의 생성자에서는 logTransaction이라는 가상함수를 호출중이기 때문입니다. 여기서 호출되는..

[Effective C++] 항목 8: 예외가 소멸자를 떠나지 못하도록 붙들어 놓자

1. 여러개의 예외는 처리가 곤란하다.만약 이러한 클래스가 있고 벡터에서 10개의 Yeoul객체를 가지고 있다고 생각해보자.class Yeoul{public: ~Yeoul(){}};void DoSomething(){ std::vectorv;} 벡터 v가 소멸될때에 벡터는 자신이 들고있던 Yeoul객체들을 소멸시켜야 할 책임을 가지고 있습니다. 만약에 첫번째 Yeoul객체를 소멸하던중 예외가 생겼다고 생각해봅시다. 나머지 9개의 객체도 소멸되어야함으로 벡터는 여전히 나머지 객체에 대해서 소멸자를 호출하게 됩니다. 그런데 두번째 Yeoul객체 역시 예외를 발생시키면 어떻게 될까요? 이렇게 예외가 2개이상이 되어버리면 C++에서 감당하기 어렵습니다. 이러한 동작의 원인은 바로 예외가 터지는 것을 내..

[Effective C++] 항목 7: 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자

1. 부모 클래스 소멸자를 virtual로 해야하는 이유우리는 기본 클래스의 소멸자는 반드시 virtual로 선언해주어야 합니다. 아래 예시를 통해서 그 이유를 알아보도록 합시다.// Effective C++ 항목 7: 다형성을 위한 기초 클래스에서는 소멸자를 virtual로 선언하자#include class GameEntity {public: // 문제: 가상 소멸자가 없음 ~GameEntity() { std::cout createGameEntity()에서 반환되는 값들은 전부 heap에 있게 됨으로 결국엔 delete를 통해 메모리를 해제해 주어야 합니다. 그러나 이렇게 되면 PlayerCharacter의 소멸자는 호출되지 않게 됩니다. 그이유는 1. createGameEntity가 반환..

[Effective C++] 항목 6: 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자

1. 개요블로그의 주인장인 여울은 게임을 사랑하는 개발자이다. 여울은 게임을 소개하는 프로그램을 만들었데 이 프로그램에는 게임을 나타내는 클래스가 있다.class Game {}; 그런데 이세상에 똑같은 게임이 존재할까요? 아닙니다. 똑같은 게임은 없고 모든 게임은 각자의 이름이 있고 각자의 플레이 방식이 있습니다. 즉 Game객체는 복사본을 만드는 것이 이치에 맞지 않습니다. 그래서 Game이랑 객체 자체를 복사시도를 하면 컴파일이 되지 않았으면 합니다. Game MapleStory;Game BattleGround;Game StarCraft(MapleStory); // 복사를 막아주세요!!MapleStory = BattleGround; // 복사를 막아주세요!! 프로그래머가 어떠한 기능이 수행되기를 ..

[Effective C++] 항목 5: C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자

1. 컴파일러가 저절로 선언하는 함수들 컴파일러는 직접 선언하지 않으면 자동으로 선언해주는 함수들이 있습니다. 복사 생성자생성자복사 대입 연산자소멸자class Yeoul {private: int* data; public: // 생성자 Yeoul(int val) { data = new int(val); } // 복사 생성자 Yeoul(const Yeoul& rhs) { data = new int(*rhs.data); } // 복사 대입 연산자 Yeoul& operator=(const Yeoul& rhs) { if (this != &rhs) { delete data; data = new int(*rhs.data); } return *this; ..