Menu
Coddy logo textTech

3/5/0의 법칙

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 25번째.

class가 동적 메모리와 같은 리소스를 관리할 때는 custom destructor, copy constructor, 그리고 이동 constructor가 필요하다는 것을 배웠습니다. 하지만 어떤 special member functions를 구현할지 결정하는 데 도움이 되는 지침이 있습니다. 바로 Rule of Three, Five, and Zero입니다.

세 가지 규칙(Rule of Three)은 다음과 같이 말합니다. 다음 세 가지 중 하나라도 define하면 세 가지 모두 define해야 합니다.

  • Destructor
  • Copy constructor
  • Copy assignment 연산자

Rule of Five는 이동 연산을 추가하여 최신 C++에서 이를 확장합니다.

  • Destructor
  • Copy constructor
  • Copy assignment 연산자
  • 이동 constructor
  • 이동 assignment 연산자
class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    
    ~Buffer() { delete[] data; }                          // 1. 소멸자
    Buffer(const Buffer& other);                          // 2. 복사 생성자
    Buffer& operator=(const Buffer& other);               // 3. 복사 대입
    Buffer(Buffer&& other) noexcept;                      // 4. 이동 생성자
    Buffer& operator=(Buffer&& other) noexcept;           // 5. 이동 대입
};

Rule of Zero는 가장 간단한 접근 방식입니다. 클래스가 리소스를 직접 관리하지 않는다면 이러한 함수들을 정의하지 마세요. 컴파일러가 해당 함수들을 생성하도록 하거나, 리소스를 대신 처리해 주는 스마트 포인터와 표준 컨테이너를 사용하세요.

class Player {
    std::string name;              // std::string이 자체 메모리를 관리합니다
    std::vector<int> scores;       // std::vector가 자신의 리소스를 처리합니다
public:
    Player(std::string n) : name(n) {}
    // 소멸자, 복사 또는 이동 함수가 필요 없습니다!
};

이러한 규칙을 따르면 일부 연산은 정의되어 있지만 다른 연산은 누락되었을 때 발생하는 이중 삭제, 메모리 누수, 댕글링 포인터와 같은 버그를 방지할 수 있습니다.

challenge icon

챌린지

쉬움

TextBuffer class를 만들어 Rule of Five를 따르도록 해 봅시다. 동적으로 할당된 문자 data를 올바르게 관리하기 위해 다섯 가지 특수 멤버 함수를 모두 구현합니다. 이를 통해 복사 및 이동 연산이 함께 작동하여 견고한 리소스 관리 class를 만드는 방법을 확인할 수 있습니다.

코드를 정리하기 위해 두 개의 파일을 만들 것입니다.

  • TextBuffer.h: 동적으로 할당된 문자 배열에 텍스트를 저장하는 TextBuffer classdefine합니다. class에는 다음이 필요합니다.
    • Private 멤버: 텍스트 content를 위한 char* 포인터 data와 문자열 길이(널 종결자를 포함하지 않음)를 위한 size_t length
    • C 문자열(const char*)을 받으며 메모리를 할당하고, content를 복사한 다음 "TextBuffer created: <text>"를 출력하는 매개변수가 있는 constructor
    • 메모리가 null이 아닌 경우 메모리를 해제하고 "TextBuffer destroyed"를 출력하는 destructor
    • deep 복사를 수행하고 "TextBuffer copied"를 출력하는 copy constructor
    • self-assignment를 처리하고, 기존 data를 정리하며, deep 복사를 수행하고 "TextBuffer copy-assigned"를 출력하는 copy assignment 연산자. *this를 반환합니다.
    • 소유권을 이전하고 "TextBuffer moved"를 출력하는 (noexcept로 표시된) move constructor. 소스는 유효한 빈 상태로 Leave합니다.
    • self-assignment를 처리하고, 기존 data를 정리하며, 소유권을 이전하고 "TextBuffer move-assigned"를 출력하는 (noexcept로 표시된) move assignment 연산자. *this를 반환합니다.
    • 저장된 텍스트를 반환하는 getText() 메서드 (data가 null이면 빈 문자열 ""을 반환)
    • 길이를 반환하는 getLength() 메서드
  • main.cpp: 다섯 가지 특수 멤버 함수를 모두 실제로 사용하는 모습을 보여 줍니다. 입력에서 텍스트 문자열을 읽은 다음 다음을 수행합니다.
    • 입력 텍스트로 original이라는 TextBufferCreate합니다.
    • original에서 copy constructor를 사용하여 copiedCreate합니다.
    • "Temporary" 텍스트로 anotherCreate합니다.
    • copy assignment를 사용합니다: another = original
    • std::move()를 사용하여 original에서 이동 생성해 movedCreate합니다.
    • "Target" 텍스트로 targetCreate합니다.
    • move assignment를 사용합니다: target = std::move(copied)
    • "--- Final State ---"를 출력합니다.
    • 각 버퍼(original, copied, moved, another, target)에 대해 "original: <text> (length: <len>)"을 출력합니다.

이동이 끝난 후 소스 객체(originalcopied)는 길이가 0인 빈 텍스트를 표시해야 하며, 대상 객체는 이전된 data를 보유해야 합니다. 이는 Rule of Five가 실제로 작동하는 모습을 보여 줍니다. 즉, 안전한 리소스 관리를 보장하기 위해 다섯 가지 함수가 모두 함께 작동합니다.

strlenstrcpy와 같은 문자열 함수에는 <cstring>을 포함하고, std::move()에는 <utility>를 포함합니다.

직접 해보기

#include <iostream>
#include <string>
#include <utility>
#include "TextBuffer.h"

using namespace std;

int main() {
    string input;
    getline(cin, input);

    // TODO: 입력 텍스트로 'original'이라는 TextBuffer 생성

    // TODO: 'original'의 복사 생성자를 사용하여 'copied' 생성

    // TODO: 텍스트 "Temporary"로 'another' 생성

    // TODO: 복사 할당 사용: another = original

    // TODO: std::move()를 사용하여 'original'에서 이동 생성으로 'moved' 생성

    // TODO: 텍스트 "Target"으로 'target' 생성

    // TODO: 이동 할당 사용: target = std::move(copied)

    // TODO: "--- Final State ---" 출력

    // TODO: 각 버퍼의 상태를 다음 형식으로 출력:
    // "original: <text> (length: <len>)"
    // 출력 대상: original, copied, moved, another, target

    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C++ 컴파일러