본문 바로가기

Effective C++

항목 12. 객체의 모든 부분을 빠짐없이 복사하자. 우선 예를 통해서 왜 객체의 모든 부분을 빠짐없이 복사해야 하는지 그 이유를 알아 봅시다. #include using namespace std; class Customer{ char* name; public: Customer():name(0){} Customer(char * _name) { name = new char[strlen(_name) +1]; strcpy(name, _name); } Customer(const Customer& c) { name = new char[strlen(c.name) +1]; strcpy(name, c.name); } ~Customer(){delete[] name;} Customer& operator=(const Customer& c) { //자기대입을 위해 swap함수 .. 더보기
항목 9. 객체 생성 및 소멸 과정중에는 절대 가상 함수를 호출하지 말자!!! 일단은 객체의 생성 과정중에 가상함수를 호출 하면 어떤일이 발생하는지 알아 보겠는데, 그전에 객체의 생성과정중 객체 생성 순서를 알아 보도록 하겠습니다. #include using namespace std; class Base { public: Base(){cout 더보기
항목 8. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 #include #include using namespace std; class DBConnection { public: //DBConnection 객체를 반환하는 함수. static DBConnection create() { cout 더보기
[EC++] 항목 7. 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자. Effective C++에 있는 내용이라고 겁먹지 말자. 우리는 이미 이 내용을 제가 C++ 포스팅 하면서 언급을 한 적이 있습니다. 왜 다형성을 가진 기본 클래스에서는 소멸자를 가상 소멸자로 써야 하는가? 우선 다형성과 그 이유에 대해서 먼저 보시죠. 다형성 이란? Virtual 소멸자 위 두 포스팅만 보더라도 왜 가상 소멸자를 쓰는지 이유는 충분히 알 수 있을 것입니다. 가상 함수를 C++에서 구현하려면 클래스에 별도의 자료구조가 하나 들어가야 합니다. 이 자료구조는 프로그램 실행 중에 주어진 객체에 대해 어떤 가상 함수를 호출해야 하는지는 결정하는 데 쓰이는 정보인데, 실제로는 포인터의 형태를 취하는 것이 대부분이고, 이를 가상 함수 테이블 포인터(Virtual table pointer) 즉, vp.. 더보기
[EC++] 항목 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자 이 항목은 이전 항목 5와 연장선상에 있는 항목이라고 할 수 있는데요, 이 세상에 복사가 불가능한 유일한 문서가 있다고 가정해 봅시다. 그 문서를 이름이 Unique_Doc 이라고 해 봅시다. 이 Unique_Doc를 나타내는 클래스가 있다고 해봅시다. class Unique_Doc { ................. } 이 객체는 복사가 불가능하므로 이것의 사본(copy)을 만드는 것 자체가 이치에 맞지 않는다고 볼 수 있습니다. 그래서 Unique_Doc 객체를 복사하는 아래와 같은 코드는 컴파일 되지 않았으면 하는 생각을 가지게 됩니다. void main() { Unique_Doc Ud1; Unique_Doc Ud2; Unique Ud3(Ud1); //경고 : 절대 사용하지 마시오!! Ud1 = U.. 더보기
[EC++] 항목 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 만약 우리가 클래스를 만들때, 클래스안에 아무것도 넣지 않았다면, 컴파일러가 복사 생성자(copy constructor), 복사 대입 연산자(copy assignment operator), 소멸자(destructor)를 저절로 선언해 주게 됩니다. 이때 컴파일러가 만드는 함수의 형태는 모두 기본형이고 public 멤버 이면서 inline 함수 입니다. class Empty(){}; 즉, 위와 같이 선언된 클래스는 아래와 같다는 이야기 입니다. class Empty{ public: Empty() {} //기본 생성자 Empty(const Empty& emt){} //복사 생성자 ~Empty(){} //소멸자 Empty& operator = (const Empty& emt){} //복사 대입 연산자 }; 기.. 더보기
[EC++] 항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자 대입과 초기화를 구분하자 class B {...}; class A { public: A(const std::string& name, const std::string& address, const std::list& phone); private: std::string theName; std::string theAddress; std::list thePhone; int num; }; A::A(const std::string& name, const std::string& address, const std::list& phone) { thName = name; theAddress = address; thePhone = phone; num = 0; } C++규칙에 의하면 어떤 객체이든 그 객체의 데이터 멤버는 생성.. 더보기
[EC++] 항목 20. 값에 의한 전달보다는 상수 객체 참조자에 의한 전달 방식을 택하는 편이 대게 낫다. 우선 이번 항목에서는 쟁점이라고 할 수 있는 것은 Pass by Value(Call by value) 의 두가지 문제점을 제기 하는데요. 첫번째는 바로 고비용 문제 입니다. 기본적으로 C++는 함수로부터 객체를 전달받거나 함수에 객체를 전달할 때 값에 의한 전달 방식을 사용하는데요. 특별히 다른 방식을 지정하지 않는 한, 함수 매개변수는 실제 인자의 '사본'을 통해 초기화되며, 어떤 함수를 호출 한 쪽은 그 함수가 반환한 값의 사본을 돌려받습니다. 이들 사본을 만들어 내는 곳이 바로 복사 생성자인데, 이런 점 때문에 고비용의 연산이 되기도 합니다. 한번 예제를 보면서 알아 보도록 하겠습니다. #include #include using namespace std; class person{ public: pe.. 더보기