둠치킨
코딩하는 둠치킨
둠치킨

블로그 메뉴

  • 홈
  • 분류 전체보기 (218)
    • BOJ (171)
      • 스택 (14)
      • 큐 (5)
      • 덱 (4)
      • 그래프 (30)
      • 배열 (8)
      • 재귀 (12)
      • 브루트 포스 (2)
      • 그리디 알고리즘 (7)
      • 다이내믹 프로그래밍 (13)
      • 백트래킹 (24)
      • 기하학 (4)
      • 트리 (4)
      • 구현 (14)
      • 수학 (3)
      • 맵 (1)
      • 다익스트라 (2)
      • 누적합 (5)
    • 자료구조 (14)
      • 스택 (3)
      • 큐 (5)
      • 덱 (2)
      • 그래프 (1)
      • 트리 (1)
      • 힙 (1)
      • 정렬 (1)
    • C++ (11)
      • 모두의코드 (2)
      • Effective C++ (3)
      • C++ STL (6)
    • 컴파일러 (1)
    • OS (17)
    • 컴퓨터 구조 (2)
    • Unreal Engine 5 (2)

공지사항

전체 방문자
오늘
어제

인기 글

최근 글

태그

  • BFS
  • boj
  • Bruteforce
  • C
  • C++
  • C++ STL
  • Cache Memory
  • deadlock
  • DFS
  • Effective C++
  • java
  • Mutex
  • next_permutation
  • os
  • Process
  • rotate
  • semaphore
  • spin lock
  • STL
  • STL C++
hELLO · Designed By 정상우.
둠치킨

코딩하는 둠치킨

C++/Effective C++

Effective C++ 공부 (항목 11 ~ 15)

2025. 6. 25. 15:50

Effective C++ 요약 (항목 11~15)


항목 11: operator=에서는 자기 대입에 대한 처리를 빠뜨리지 말자

문제점

arr[i] = arr[j];
*px = *py;
  • 위 연산들에는 자기 대입(self-assignment)의 가능성이 있음.
  • 단순히 delete 후 new로 처리할 경우 자기 대입 시 이미 지워진 데이터를 참조하게 될 수 있음.

안전한 방법

Widget& Widget::operator=(const Widget& rhs) {
    if (this == &rhs) return *this;

    Bitmap* pOrig = pb;
    pb = new Bitmap(*rhs.pb);  // 복사 성공 시에만 교체
    delete pOrig;

    return *this;
}
  • 복사 먼저 → delete 순으로 예외 안전성 확보.
  • 성능을 고려한다면 이후 항목 29의 “복사 후 교환(copy-and-swap)” 기법도 고려 가능.

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

객체 복사 함수 2개

  • 복사 생성자
  • 복사 대입 연산자

실수 예시

class Customer {
public:
    Customer(const Customer& rhs);
    Customer& operator=(const Customer& rhs);
private:
    std::string name;
};

Customer::Customer(const Customer& rhs)
    : name(rhs.name) { logCall("copy ctor"); }

Customer& Customer::operator=(const Customer& rhs) {
    logCall("copy assignment");
    name = rhs.name;
    return *this;
}
  • 나중에 멤버가 추가됐는데 복사 함수 수정 안 하면? → 컴파일러는 알려주지 않음!
  • 상속 관계라면 더 위험. 파생 클래스에서 기본 클래스 복사 누락 주의.

해결 방법

  • 모든 데이터 멤버 복사
  • 기본 클래스의 복사 함수 호출:
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
    : Customer(rhs), ... { ... }

PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs) {
    Customer::operator=(rhs);
    ...
}
  • 복사 생성자와 복사 대입 연산자는 같은 private 함수 호출로 공통 처리 가능. 직접 호출은 금지.

항목 13: 자원 관리에는 객체가 그만!

예외 발생 시 자원 누수

void f() {
    Investment* p = createInvestment();
    ...
    delete p;
}
  • 중간에 예외 발생하면 delete가 호출되지 않음 → 누수 발생

해결: RAII(Resource Acquisition Is Initialization)

std::unique_ptr<Investment> p(createInvestment());
  • 객체 생성과 동시에 자원 관리
  • 블록을 벗어나면 자동으로 delete 호출
  • auto_ptr은 복사 시 위험 → C++11부터는 shared_ptr, unique_ptr 사용

항목 14: 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자

RAII 클래스의 복사 방식 선택 필요:

  • 복사 금지
class Lock {
    Lock(const Lock&) = delete;
    Lock& operator=(const Lock&) = delete;
};
  • 참조 계수 방식 (shared_ptr)
std::shared_ptr<Mutex> mutexPtr;

 

  • 깊은 복사
    • 자원을 독립적으로 복제해야 하는 경우
  • 소유권 이전 (move)
    • auto_ptr처럼 소유권 넘기기 (요즘은 unique_ptr로 대체)

항목 15: 자원 관리 클래스에 관리되는 자원은 외부에서 접근할 수 있게 하자

문제

int daysHeld(const Investment* pi);
std::shared_ptr<Investment> pInv(createInvestment());

int days = daysHeld(pInv); // ❌ 컴파일 에러
 
  • 스마트 포인터는 원시 포인터로 자동 변환되지 않음

해결

int days = daysHeld(pInv.get()); // 명시적 변환

또는

bool taxable = !pInv->isTaxFree(); // 암시적 변환 (operator->, operator*)
  • 잘 설계된 RAII 클래스는 get, operator*, operator-> 제공
  • 타입 안정성과 명확성을 위해 명시적 변환만 제공하는 것도 고려 가능
저작자표시 (새창열림)

'C++ > Effective C++' 카테고리의 다른 글

Effective C++ 공부 (항목 6 ~ 10)  (0) 2025.06.24
Effective C++ 공부 (항목 1 ~ 5)  (0) 2025.06.23
    'C++/Effective C++' 카테고리의 다른 글
    • Effective C++ 공부 (항목 6 ~ 10)
    • Effective C++ 공부 (항목 1 ~ 5)
    둠치킨
    둠치킨
    코딩 공부를 위한 코딩 블로그 기록 일기

    티스토리툴바