본문 바로가기

C++21

항목 25 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 swap함수는 우선 일반적으로 이런식으로 구현되어있다. namespace std { template void temp(T& a, T& b) { T temp(a); a = b; b = temp; } } 그래서 우리가 일반적인 std::swap의 기능을 이용하면 복사가 필수적으로 발생하기 때문에 여러모로 손해를 보는 경우가 있다. class WidgetImpl { public: ... private: int a, b, c; std::vector v; }; class Widget { public: Widget(const Widget& rhs); Widget& operator=(const Widget& rhs) { ... *pImpl = *(rhs.pImpl); ... } ... private: WidgetIm.. 2024. 1. 24.
항목 24 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자 자 이번 항목은 암시적 변환을 허용하는 클래스에 대한 내용이다. 우선 아래와 같은 타입의 클래스가 있다고 치자. class Rational { public: Rational(int numerator = 0, int denominator = 1); int numerator() const; int denominator() const; private: ... }; 대충 분수를 나타내는 클래스이다. 우리는 여기서 각 Rational 과의 곱셈을 할 수 있도록 하기 위해서 operator*를 멤버함수로 만들수 있다. class Rational { public: ... const Rational operator*(const Rational& rhs) const; }; 자, 이렇게 되면 우리는 아래와 같은 식을 작성.. 2024. 1. 22.
항목 23 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 자 이번 항목은 클래스의 캡슐화와 정말 밀접하게 관련있는 항목이다. 자 우선 웹브라우저를 나타내는 클래스가 하나 있다고 가정하자. 웹브라우저 클래스라면 멤버함수로 제공하는 것들이 상당히 많을 것이다. 웹브라우저로 다운로드한 임시 저장 캐시를 비우는 함수, 방문한 URL 기록을 없애는 함수, 시스템이 갖고 있는 쿠키를 제거하는 함수 등등이 있을 것이다. class WebBrowser { public: ... void clearCache(); void clearHistory(); void removeCookies(); ... }; 하지만 여기서 이 세 작업을 한 번에 하고싶은 사람도 있을 수 있기 때문에 이 세 함수를 모아서 불러주는 함수도 준비해 둘수 있다. class WebBrowser { public:.. 2024. 1. 21.
항목 22 데이터 멤버가 선언될 곳은 private 영역임을 명심하자 이번항목은 뭔가 길게 설명되어 있지만 사실 축약하면 별 내용이아니라서 간단하게만 설명하려고 한다. 우선, 제목 그대로 데이터 멤버가 선언될 곳은 private 영역이어야 한다. 우리가 데이터를 public 영역에 구현한다면 데이터가 외부에 노출될 가능성이 있다. 즉 캡슐화를 하지 못한다는 것이다. 또한 public 영역에 구현을 해놓았다면 멤버값이 어디서 사용되는지 알아내기가 정말 어렵다. 그래서 앞으로는 private영역에 우선 선언을 하자. 그리고 아래 방법을 이용하자. class AccessLevels { public: ... int getReadOnly() const { return readOnly; } void setReadWrite(int value) { readWrite = value; } .. 2024. 1. 21.
항목 21 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자 자, 제목그대로 이번 항목은 함수에서 객체를 반환해야 할경우 참조자를 반환하려 하지 말라는 것이다. 아래 코드를 보도록 하자. class MyNumber { public: explicit MyNumber(int value=0); ... private: int d; friend const MyNumber operator* (const MyNumber& lhs, const MyNumber& rhs); }; 자 이런식으로 사용자 정의 숫자 클래스를 만들고 operator*를 오버로딩하여 서로 곱할 수 있도록 만들었다. 자 여기서 우리는 operator*의 반환 값으로 참조자를 반환하면 복사비용을 줄일 수 있지 않나? 라고 생각할 수 있다. 그렇다면 참조자라는 것은 원본 객체가 있어야 하는데 도대체 어떤 객체에.. 2024. 1. 21.
항목 20 '값에 의한 전달'보다는 '상수객체 참조자에 의한 전달'방식을 택하는 편이 대개 낫다 사실 값에 의한 전달보다 상수객체 참조자에 의한 전달 방식을 사용하라는 것은 이미 많이 들어서 알것이다. 하지만 나는 여기서 값에 의한 전달을 했을때 복사 비용이 커서 문제가 된다고만 생각을 했었는데 그 뿐만이 아니었다. 아래 코드를 한 번 보자. class Window { // 윈도우를 나타내는 기본 클래스 public: ... virtual void display() const; // window를 그림 }; class WindowWithScrollBars: public Window { public: ... virtual void display() const; // 스크롤 바가 있는 윈도우를 그림 }; void DrawAnyWindow(Window w) { w.display(); } 자 이런식으로 W.. 2024. 1. 20.
항목 19 클래스 설계는 타입 설계와 똑같이 취급하자 자, 사실 제목이 너무 당연한 소리이긴 하다. 클래스 자체가 사용자가 직접 정의한 타입이니까 말이다. 하지만 이번 항목에서는 그런 당연한 소리를 하려고 만들어진 것이 아니다. 이번 항목에서는 우리가 클래스를 설계할 때 스스로에게 던져야할 질문들을 모아놓았다. 그 질문들을 하나씩 살펴보도록 하자. 1. 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? 이 부분에 따라 클래스의 생성자와 소멸자의 설계가 바뀐다. 또한 메모리 할당함수(operator new, operator delete)를 직접 작성 할 경우에는 이들 함수의 설계에도 영향을 미친다. 2. 객체 초기화는 객체 대입과 어떻게 달라야 하는가? 생성자와 대입 연산자의 동작 및 둘의 차이점을 결정짓는 것이다. 초기화와 대입을 헷갈려서.. 2024. 1. 20.
항목 18 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 자 우선 인터페이스란 무엇일까? 인터페이스는 사실 우리가 코드로 작성하여 응용할 수 있는것은 모두 인터페이스다. 함수, 클래스, 템플릿 등 왠만한 것은 다 인터페이스 라고 보면 된다. 그렇다면 이제 항목 18의 제목대로 제대로 쓰기엔 쉽고 엉터리로 쓰기엔 어려운 인터페이스는 어떻게 만들 수 있을까? 우선 날짜를 나타내는 어떤 클래스에 넣을 생성자를 설계하고 있다고 가정하자. class Date { public: Date(int month, int day, int year); ... }; 자 이 클래스는 별 문제가 없어 보인다. 하지만 매개변수의 전달 순서가 잘못될 여지가 열려있다. Date d(20, 1, 2024); // 1, 20, 2024 여야하는데 20, 1을 넣어버렸다! 또한 월, 일, 연도와 .. 2024. 1. 20.
항목 17 new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 항목16은 메모리를 해제 할 때 delete를 쓸지 delete[]를 쓸지 그 상황에 맞추어서 잘 쓰라는 내용이었는데 이건 뭐 C++ 기본 문법에 나오는 내용이라 당연한 소리여서 그냥 건너 뛰었다. (물론 책은 읽음) 자, 항목 17은 제대로 안보면 상당히 헷갈리는 부분이다. 우선 아래와 같이 처리 우선 순위를 알려주는 함수가 있고 그 처리 우선 순위에 따라 Widget을 처리해주는 함수가 있다고 치자. int priority(); void processWidget(std::shared_ptr pw, int priority); 그래서 우리는 processWidget 함수를 다음과 같이 호출한다. void processWidget(new Widget, priority()); 하지만 이 코드는 컴파일되지 않.. 2024. 1. 19.