ProgramingTip

클래스를 위해 컴파일러가 만든 모든 멤버 함수는 무엇입니까?

bestdevel 2020. 12. 12. 12:12
반응형

클래스를 위해 컴파일러가 만든 모든 멤버 함수는 무엇입니까? 그게 항상 일어나나요?


클래스를 위해 컴파일러가 만든 모든 멤버 함수는 무엇입니까? 그게 항상 일어나나요? 소멸자처럼. 내 관심사는 모든 클래스에 대해 생성 여부와 기본 생성자가 필요한 이유는 무엇입니까?


C ++ 98/03

필요한 경우

  1. 사용자가 직접 생성 할 가능성이없는 한 컴파일러는 기본 생성자 생성합니다 .
  2. 는 컴파일러 user-가 직접 선언하지 않는 복사 생성자생성합니다 .
  3. 사용자가 직접 선언하지 않는 한 컴파일러는 복사 할당 연산자생성합니다 .
  4. 컴파일러는 여러분이 선언하지 않는 소멸자생성합니다 .

Péter가 유용한 주석에서 말했듯이 모든 것이 필요할 때만 컴파일러에 의해 생성 됩니다. (차이점은 컴파일러가 생성 할 수없는 경우 사용하지 않는 한 괜찮다는 것입니다.)


C ++ 11

C ++ 11은 C ++ 14에도 적용되는 다음 규칙을 추가합니다 (towi에 대한, 주석 참조 ) .

  • 는 다음과 컴파일러 같은 경우 이동 생성자를 생성합니다.
    • 에는 user-가 거기 선언되지 않습니다 복사 생성자
    • 에는 user-가 거기 선언되지 않습니다 복사 할당 연산자
    • 에는 사용자가 선언이없는 이동 할당 연산자가
    • 사용자가 선언 한 소멸자 가 없습니다 .
    • 그것은되어 있지 표시 delete, D를
    • 그리고 모든 구성원과 기지는 움직일 수 있습니다.
  • 이동 할당 연산자의 생성 경우유사하게 다음과 같은 경우입니다.
    • 에는 user-가 거기 선언되지 않습니다 복사 생성자
    • 에는 user-가 거기 선언되지 않습니다 복사 할당 연산자
    • user-가 선언에는이없는 이동 생성자
    • 사용자가 선언 한 소멸자 가 없습니다 .

    • 그것은되어 있지 표시 delete, D를
    • 그리고 모든 구성원과 기지는 움직일 수 있습니다.

C ++ 03 규칙보다 조금 더 정교하며 실제로 더 의미가 있습니다.

위의 내용을 더 쉽게 이해 광고주 :

class Thing {
public:
    Thing();                        // default constructor
    Thing(const Thing&);            // copy c'tor
    Thing& operator=(const Thing&); // copy-assign
    ~Thing();                       // d'tor
    // C++11:
    Thing(Thing&&);                 // move c'tor
    Thing& operator=(Thing&&);      // move-assign
};

더 읽을 거리 : 만약 당신이 C ++ 초보자라면 마르틴 페르난데스가 작성한 기사 에서 원래 5 가지 일명 제로의 지배 를 구현할 필요가없는 디자인을 고려해 보십시오 .


'created'에 의해 'defined'를 의미합니까?

$ 12.1- "기본 생성자 (12.1), 복사 생성자 및 복사 할당 연산자 (12.8) 및 소멸자 (12.4)는 특수 멤버 함수입니다.

'생성됨'이 '정의 됨'을 의미하는 경우 다음은 C ++ 표준의 중요한 부분입니다.

-클래스에 대해 암시 적으로 선언 된 기본 생성자는 클래스 유형 (1.8)의 개체를 만드는 데 적용 할 때 암시 적으로 정의됩니다.

-클래스에 사용자가 선언 한 소멸자가없는 경우 소멸자는 암시 적으로 선언됩니다. 암시 적으로 선언 된 소멸자는 클래스 유형의 개체를 소멸하는 데 때 암시 적으로 정의됩니다.

-클래스 정의가 복사 생성 암시 명시 적으로 선언되지 않습니다. 암시 적으로 선언 된 복사 생성자는 해당 클래스 형식의 개체 또는 해당 클래스 형식에서 파생 된 클래스 형식의 복사본에서 해당 클래스 형식의 개체를 사용하는 경우 암시 적으로 정의됩니다.

-클래스 정의가 할당 연산자를 명시 적으로 선언하지 암시 적으로 선언됩니다. 암시 적으로 선언 된 복사 할당 연산자는 해당 클래스 유형의 객체에 해당 클래스 유형의 값 또는 해당 클래스 유형에서 파생 된 클래스 유형의 값이 할당 될 때 암시 적으로 정의됩니다.


기본적으로 사용자가 구현하지 않은 경우 컴파일러는 일부 멤버 함수를 클래스에 추가합니다. 문의를 빅 4라고합니다.

  • 기본 생성자
  • 복사 생성자
  • 복사 연산자 (할당)
  • 폐물 소각로

멤버 유형 및 생성 멤버 함수에 따라 사용자가 직접 제공하는 멤버 기능이 없습니다.


C ++ 17 N4659 표준 초안

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 6.1 "선언 및 정의"에는 모두를 요약하는 메모가 있습니다.

3 [참고 생성 : 일부 상황에서 C ++ 구현은 기본 생성자 (15.1), 복사 생성자 (15.8), 이동 할당 연산자 (15.8), 복사 할당 연산자 (15.8), 이동 할당 연산자 (15.8) 또는 소멸자 (15.4) 멤버 함수 . — end note] [예 : 주어진

#include <string>

struct C {
  std::string s;         // std::string is the standard library class (Clause 24)
};

int main() {
  C a;
  C b = a;
  b = a;
}

구현은 C의 정의를 다음과 동일하게 만드는 함수를 암시 적으로 정의합니다.

struct C {
  std::string s;
  C() : s() { }
  C(const C& x): s(x.s) { }
  C(C&& x): s(static_cast<std::string&&>(x.s)) { }
  // : s(std::move(x.s)) { }
  C& operator=(const C& x) { s = x.s; return *this; }
  C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
  // { s = std::move(x.s); return *this; }
  ~ C() { }
};

— 최종 예]

선언 된 조건은 다음에서 설명합니다. 기본 / 복사 / 이동 및 복사 / 이동 할당 연산자의 자동 생성 조건?

어떤 방법에 있는지 확인하는 방법 = default은 다음에 설명 된대로 보는 것입니다 . "음성"은 클래스의 함수 선언 무엇을 의미합니까?

아래 예제는이를 수행하고 암시 적으로 정의 된 모든 함수를 실행합니다.

#include <cassert>
#include <string>

struct Default {
    int i;
    Default()                          = default;
    Default(const Default&)            = default;
    Default& operator=(Default&)       = default;
    Default& operator=(const Default&) = default;
    Default(Default&&)                 = default;
    Default& operator=(Default&&)      = default;
    ~Default()                         = default;
};

struct Instrument {
    int i;
    static std::string last_call;
    Instrument()                             { last_call = "ctor"; }
    Instrument(const Instrument&)            { last_call = "copy ctor"; }
    Instrument& operator=(Instrument&)       { last_call = "copy assign"; return *this; }
    Instrument& operator=(const Instrument&) { last_call = "copy assign const"; return *this; }
    Instrument(Instrument&&)                 { last_call = "move ctor";  }
    Instrument& operator=(Instrument&&)      { last_call = "move assign"; return *this; }
    ~Instrument()                            { last_call = "dtor"; }
};
std::string Instrument::last_call;

int main() {
    // See what the default constructors are doing.
    {
        // Default constructor.
        Default ctor;
        // i is uninitialized.
        // std::cout << ctor.i << std::endl;
        ctor.i = 1;

        // Copy constructor.
        Default copy_ctor(ctor);
        assert(copy_ctor.i = 1);

        // Copy assignment.
        Default copy_assign;
        copy_assign = ctor;
        assert(copy_assign.i = 1);

        // Copy assignment const.
        const Default const_ctor(ctor);
        Default copy_assign_const;
        copy_assign_const = const_ctor;
        assert(copy_assign_const.i == 1);

        // Move constructor.
        Default move_ctor(std::move(ctor));
        assert(move_ctor.i == 1);

        // Move assignment.
        Default move_assign;
        move_assign = std::move(ctor);
        assert(move_assign.i == 1);
    }

    // Check that the constructors are called by these calls.
    {
        // Default constructor.
        Instrument ctor;
        assert(Instrument::last_call == "ctor");

        // Copy constructor.
        Instrument copy_ctor(ctor);
        assert(Instrument::last_call == "copy ctor");

        // Copy assignment.
        copy_ctor = ctor;
        assert(Instrument::last_call == "copy assign");

        // Copy assignment const.
        const Instrument const_ctor(ctor);
        Instrument copy_assign_const;
        copy_assign_const = const_ctor;
        assert(Instrument::last_call == "copy assign const");

        // Move constructor.
        Instrument move_ctor(std::move(ctor));
        assert(Instrument::last_call == "move ctor");

        // Move assignment.
        Instrument move_assign;
        move_assign = std::move(ctor);
        assert(Instrument::last_call == "move assign");

        // Destructor.
        {
            Instrument dtor;
        }
        assert(Instrument::last_call == "dtor");
    }
}

GitHub 업스트림 .

GCC 7.3.0으로 테스트 됨 :

g++ -std=c++11 implicitly_defined.cpp

다른 답변은 생성 된 내용을 알려 주거나 생성 할 수 있습니다.

내 관심사는 모든 클래스에 대해 생성 여부입니다.

왜 걱정합니까? 실행 파일에 원하지 않는 코드를 생성한다고 생각하십니까? 가능성은 낮지 만 환경에 따라 쉽게 확인할 수 있습니다.

아니면 당신이 원할 때 생성자를 만들지 않을 수도 있다는 우려가 있었습니까? 걱정할 필요가 없습니다. 필요한 경우 항상 생성되며 사용자가 제공하지 않습니다.

... 기본 생성자가 필요한 이유는 무엇입니까?

클래스에는 체계적으로 호출해야하는 자체 소멸자가있는 개체가 내부에있을 수 있기 때문입니다. 예를 들어, 주어진 ...

struct X
{
    std::string a;
    std::string b;
};

... 기본 소멸자는 a와 b의 소멸자가 실행되도록합니다.

참고 URL : https://stackoverflow.com/questions/3734247/what-are-all-the-member-functions-created-by-compiler-for-a-class-does-that-hap

반응형