다음을 통해 공유


값 형식으로서의 C++ 클래스

C++ 클래스는 기본적으로 값 형식입니다. 개체 지향 프로그래밍을 지원하기 위해 다형 동작을 지원하는 참조 형식으로 지정할 수 있습니다. 값 형식은 메모리 및 레이아웃 컨트롤의 관점에서 볼 수 있는 반면 참조 형식은 다형성을 위해 기본 클래스 및 가상 함수에 관한 것입니다. 기본적으로 값 형식은 복사 가능하므로 항상 복사 생성자와 복사 할당 연산자가 있습니다. 참조 형식의 경우 클래스를 복사할 수 없게 만들고(복사 생성자 및 복사 할당 연산자를 사용하지 않도록 설정) 의도한 다형성을 지원하는 가상 소멸자를 사용합니다. 또한 값 형식은 콘텐츠에 관한 것이며, 복사할 때는 항상 별도로 수정할 수 있는 두 개의 독립적인 값을 제공합니다. 참조 형식은 ID에 관한 것입니다. 개체의 종류는 무엇인가요? 이러한 이유로 "참조 형식"을 "다형 형식"이라고도 합니다.

참조와 유사한 형식(기본 클래스, 가상 함수)을 원하는 경우 다음 코드의 클래스에 MyRefType 표시된 것처럼 복사를 명시적으로 사용하지 않도록 설정해야 합니다.

// cl /EHsc /nologo /W4

class MyRefType {
private:
    MyRefType & operator=(const MyRefType &);
    MyRefType(const MyRefType &);
public:
    MyRefType () {}
};

int main()
{
    MyRefType Data1, Data2;
    // ...
    Data1 = Data2;
}

위의 코드를 컴파일하면 다음 오류가 발생합니다.

test.cpp(15) : error C2248: 'MyRefType::operator =' : cannot access private member declared in class 'MyRefType'
        meow.cpp(5) : see declaration of 'MyRefType::operator ='
        meow.cpp(3) : see declaration of 'MyRefType'

값 형식 및 이동 효율성

새 복사 최적화로 인해 복사 할당 오버헤드가 방지됩니다. 예를 들어 문자열의 벡터 중간에 문자열을 삽입하는 경우 벡터 자체의 증가가 발생하더라도 복사 재할당 오버헤드는 없으며 이동만 있습니다. 이러한 최적화는 다른 작업(예: 두 개의 거대한 개체에 대한 추가 작업 수행)에도 적용됩니다. 이러한 값 작업 최적화를 사용하도록 설정하려면 어떻게 해야 할까요? 컴파일러를 사용하면 복사 생성자가 컴파일러에서 자동으로 생성될 수 있는 것처럼 암시적으로 사용할 수 있습니다. 그러나 클래스 정의에서 할당을 선언하여 할당을 이동하고 생성자를 이동하려면 클래스가 "옵트인"해야 합니다. Move는 적절한 멤버 함수 선언에서 이중 앰퍼샌드(&> rvalue) 참조를 사용하고 이동 생성자 및 이동 할당 메서드를 정의합니다. 또한 원본 개체에서 "배짱을 도용"하는 올바른 코드를 삽입해야 합니다.

이동 작업을 사용하도록 설정해야 하는지 여부를 어떻게 결정합니까? 복사 생성을 사용하도록 설정해야 한다는 것을 이미 알고 있는 경우 특히 딥 카피보다 저렴할 경우 이동 생성을 사용하도록 설정하려고 할 수 있습니다. 그러나 이동 지원이 필요하다고 해서 반드시 복사 작업을 사용하도록 설정하려는 것은 아닙니다. 이 후자의 경우를 "이동 전용 형식"이라고 합니다. 표준 라이브러리에 이미 있는 예는 .입니다 unique_ptr. 참고로 이전 auto_ptr 버전은 사용되지 않으며 이전 버전의 C++에서 이동 의미 체계 지원이 부족하여 정확하게 대체 unique_ptr 되었습니다.

이동 의미 체계를 사용하여 값으로 반환하거나 중간에 삽입할 수 있습니다. 이동은 복사 최적화입니다. 해결 방법으로 힙 할당이 필요하지 않습니다. 다음 의사 코드를 살펴보겠습니다.

#include <set>
#include <vector>
#include <string>
using namespace std;

//...
set<widget> LoadHugeData() {
    set<widget> ret;
    // ... load data from disk and populate ret
    return ret;
}
//...
widgets = LoadHugeData();   // efficient, no deep copy

vector<string> v = IfIHadAMillionStrings();
v.insert( begin(v)+v.size()/2, "scott" );   // efficient, no deep copy-shuffle
v.insert( begin(v)+v.size()/2, "Andrei" );  // (just 1M ptr/len assignments)
//...
HugeMatrix operator+(const HugeMatrix& , const HugeMatrix& );
HugeMatrix operator+(const HugeMatrix& ,       HugeMatrix&&);
HugeMatrix operator+(      HugeMatrix&&, const HugeMatrix& );
HugeMatrix operator+(      HugeMatrix&&,       HugeMatrix&&);
//...
hm5 = hm1+hm2+hm3+hm4+hm5;   // efficient, no extra copies

적절한 값 형식에 대해 이동 사용

딥 카피보다 이동이 저렴할 수 있는 가치와 유사한 클래스의 경우 효율성을 위해 이동 생성 및 이동 할당을 사용하도록 설정합니다. 다음 의사 코드를 살펴보겠습니다.

#include <memory>
#include <stdexcept>
using namespace std;
// ...
class my_class {
    unique_ptr<BigHugeData> data;
public:
    my_class( my_class&& other )   // move construction
        : data( move( other.data ) ) { }
    my_class& operator=( my_class&& other )   // move assignment
    { data = move( other.data ); return *this; }
    // ...
    void method() {   // check (if appropriate)
        if( !data )
            throw std::runtime_error("RUNTIME ERROR: Insufficient resources!");
    }
};

복사 생성/할당을 사용하도록 설정하는 경우 딥 카피보다 저렴할 수 있는 경우 이동 생성/할당을 사용하도록 설정합니다.

일부 비값 형식은 리소스를 복제할 수 없고 소유권만 이전하는 경우와 같이 이동 전용입니다. 예: unique_ptr

참고 항목

C++ 형식 시스템
C++ 시작하기
C++ 언어 참조
C++ 표준 라이브러리