언어

언어/C++

[Effective C++] new 및 delete를 사용할 때는 형태를 반드시 맞추자

항목 16 : new 및 delete를 사용할 때는 형태를 반드시 맞추자 아래에 적어 놓은 것에서 뭔가 잘못된 점이 보이나요? 1 2 3 std::string *stringArray = new std::string[100]; ... delete stringArray; 아무런 문제가 없어 보이지만, 100개의 string 객체 가운데 99개는 정상적인 소멸과정을 거치지 못할 가능성이 큽니다. 여러분이 new 연산자를 사용해서 표현식을 꾸미게 되면, 이로 인해 두 가지의 내부 동작이 진행됩니다. 일단 메모리가 할당됩니다. 그 다음, 할당된 메모리에 대해 한 개 이상의 생성자가 호출됩니다. delete 표현식을 쓸 경우에는 또 다른 두 가지의 내부 동작이 진행되는데, 우선 기존에 할당된 메모리에 대해 한 개 ..

언어/C++

[Effective C++] 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자

항목 15 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 자원 관리 클래스는 재치 만발의 듬직한 클래스입니다. 실수로 터질 수 있는 자원 누출을 튼튼히 막아 주는 보호벽 역할을 해 주니까요. 1 std::tr1::shared_ptr pInv(createInvestment()); 이때 어떤 Investment 객체를 사용하는 함수로서 여러분이 사용하려고 하는 것이 다음과 같다고 가정해 봅시다. 1 int daysHeld(const Investment *pi); // 투자금이 유입된 이후로 경과한 날수 그리고 이렇게 호출하고 싶을 텐데요. 1 int days = daysHeld(pInv); // 에러 애석하게도 이 코드는 컴파일이 안 됩니다. daysHeld 함수는 Investme..

언어/C++

[Effective C++] 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자

항목 14 : 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 자원 관리 클래스를 스스로 만들어야 할 필요를 느끼는 경우가 있습니다. 예를 하나 들어 보죠, Mutex 타입의 뮤텍스 객체를 조작하는 C API를 사용하는 중이라고 가정합시다. 이 C API에서 제공하는 함수 중엔 lock 및 unlock이 있고요. 1 2 3 void lock(Mutex *pm); // pm이 가리키는 뮤텍스에 잠금을 겁니다. void unlock(Mutex *pm) // pm이 가리키는 해당 뮤텍스의 잠금을 풉니다. 그런데 뮤텍스 잠금을 관리하는 클래스를 하나 만들고 싶습니다. 이전에 걸어 놓은 뮤텍스 잠금을 잊지 않고 풀어 줄 목적인 거죠. 이런 용도의 클래스는 기본적으로 RAII 법칙을 따라 구성합니다. 즉, ..

언어/C++

[Effective C++] 자원 관리에는 객체가 그만!

항목 13 : 자원 관리에는 객체가 그만! 투자를 모델링해 주는 클래스 라이브러리를 가지고 어떤 작업을 한다고 가정합시다. 이 라이브러리는 Investment라는 최상위 클래스가 있고, 이것을 기본으로 하여 구체적인 형태의 투자 클래스가 파생되어 있습니다. 1 class Investment { ... }; // 여러 형태의 투자를 모델링한 클래스 계통의 최상위 클래스 가정을 하나 더 하겠습니다. 이 라이브러리는 Investment에서 파생된 클래스의 객체를 사용자가 얻어내는 용도로 팩토리 함수만을 쓰도록 만들어져 있다고요. 1 2 Investment* createInvestment(); // Investment 클래스 계통에 속한 클래스의 객체를 동적 할당하고 그 포인터를 반환합니다. // 이 객체의 해..

언어/C++

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

항목 12 : 객체의 모든 부분을 빠짐없이 복사하자 객체의 안쪽 부분만 캡슐화한 객체 지향 시스템 중 설계가 잘 된 것들을 보면, 객체를 복사하는 함수가 딱 둘만 있는 것을 알 수 있습니다. 복사 생성자와 복사 대입 연산자라고, 성격에 따라 이름도 적절히 지어져 있습니다. 이 둘을 통틀어 객체 복사 함수라고 부릅니다. 객체 복사 함수는 컴파일러가 필요에 따라 만들어내기도 합니다. 그리고 컴파일러가 생성한 복사 함수는 비록 저절로 만들어졌지만 동작은 기본적인 요구에 아주 충실합니다. 복사되는 객체가 갖고 있는 데이터를 빠짐없이 복사한다라는 것입니다. 객체 복사 함수를 여러분인 선언한다는 것은, 컴파일러가 만든 녀석의 기본 동작에 뭔가 마음에 안 드는 것이 있다는 이야기입니다. 이에 대해 컴파일러도 썩 반기..

언어/C++

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

항목 11 : operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 동적 할당된 비트맵을 가리키는 원시 포인터를 데이터 멤버로 갖는 클래스를 하나 만들었다고 가정해 봅시다. 1 2 3 4 5 6 7 class Bitmap { ... }; class Widget { ... private : Bitmap *pb; // 힙에 할당한 객체를 가리키는 포인터 }; Colored by Color Scripter 이젠 겉보기에 멀쩡해 보이는 operator=의 구현코드를 보시겠습니다. 1 2 3 4 5 6 7 8 Widget& Widget::operator=(const Widget& rhs) // 안전하지 않게 구현된 operator= { delete pb; // 현재의 비트맵 사용을 중지합니다. pb ..

언어/C++

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

항목 10 : 대입 연산자는 *this의 참조자를 반환하게 하자 C++의 대입 연산은 여러 개가 사슬처럼 엮일 수 있는 재미있는 성질을 갖고 있습니다. 1 2 3 int x, y, z; x = y = z = 15; // 대입이 사슬처럼 이어집니다. 대입 연산이 가진 또 하나의 재미있는 특성은 바로 우측 연관 연산이라는 점입니다. 이렇게 대입 연산이 사슬처럼 엮이려면 대입 연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것입니다. 1 2 3 4 5 6 7 8 9 10 class Widget { public : ... Widget& operator=(const Widget& rhs) // 반환 타입은 현재의 클래스에 대한 참조자입니다. { ... return *this; // 좌변 객체(의 참조..

언어/C++

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

항목 9 : 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 객체 생성 및 소멸 과정 중에는 가상 함수를 호출하면 절대로 안됩니다! 기본 클래스의 생성자가 호출될 도안에는, 가상 함수는 절대로 파생 클래스 쪽으로 내려가지 않습니다. 그 대신, 객체 자신이 기본 클래스 타입인 것처럼 동작합니다, 즉, 기본 클래스 생성 과정에서는 가상 함수가 먹히지 않습니다. 이 같은 동작에는 다 이유가 있습니다. 아시다시피 기본 클래스 생성자는 파생 클래스 생성자보다 앞서서 실행되기 때문에, 기본 클래스 생성자가 돌아가고 있을 시점에 파생 클래스 데이터 멤버는 아직 초기화된 상태가 아니라는 것이 핵심입니다. 이때 기본 클래스 생성자에서 어쩌다 호출된 가상 함수가 파생 클래스 쪽으로 내려간다면 어떻게 될까..

언어/C++

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

항목 8 : 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 소멸자로부터 예외가 터져 나가는 경우를 C++ 언어에서 막는 것은 아니지만, 실제 상황을 들춰보면 확실히 우리가 막을 수 밖에 없는 것 같습니다. 아래의 예를 봅시다. 1 2 3 4 5 6 7 8 class DBConnection { public : ... static DBConnection create(); // DBConnection 객체를 반환하는 함수. 매개변수는 편의상 생략. void close(); // 연결을 닫습니다. 이때 연결이 실패하면 예외를 던집니다. }; Colored by Color Scripter 보다시피 사용자가 DBConnection 객체에 대해 close를 직접 호출해야 하는 설계입니다. 자원 관리 클래스의 소멸자가 ..

언어/C++

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

항목 7 : 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 시간 기록에 관련된 TimeKeeper이라는 클래스를 선언하겠습니다. 1 2 3 4 5 6 7 8 9 10 class TimeKeeper{ public : TimeKeeper(); ~TimeKeeper(); ... }; class AtomicClock : public TimeKeeper { ... }; class WaterClock : public TimeKeeper { ... }; class WristWatch : public TimeKeeper { ... }; 이 클래스의 혜택을 받는 사용자들은 시간 정보에 접근하고 싶어 합니다. 시간 계산이 어떻게 되는지에 대해서는 신경 쓰고 싶지 않고요. 사정이 이렇기 때문에, 어..

지나가던 개발자
'언어' 카테고리의 글 목록 (8 Page)