programing

= 연산자가 정의되지 않은 구조체에서 작동하는 이유는 무엇입니까?

projobs 2021. 1. 19. 22:15
반응형

= 연산자가 정의되지 않은 구조체에서 작동하는 이유는 무엇입니까?


간단한 예를 살펴 보겠습니다.

struct some_struct {
   std::string str;
   int a, b, c;
}

some_struct abc, abc_copy;
abc.str = "some text";
abc.a = 1;
abc.b = 2;
abc.c = 3;

abc_copy = abc;

그러면 abc_copy는 .. 의 정확한 복사본 입니다 abc. = 연산자 정의 하지 않고 어떻게 가능 합니까?

(일부 코드 작업을 할 때 놀랐습니다 ..)


이 네 가지 메서드 (C ++ 11의 경우 6 개)를 정의하지 않으면 컴파일러에서 자동으로 생성합니다.

  • 기본 생성자
  • 생성자 복사
  • 할당 연산자
  • 폐물 소각로
  • 생성자 이동 (C ++ 11)
  • 이동 할당 (C ++ 11)

이유를 알고 싶다면?
C와의 하위 호환성을 유지하는 것입니다 (C 구조체는 = 및 선언을 사용하여 복사 할 수 있기 때문입니다). 그러나 간단한 클래스를 더 쉽게 작성할 수 있습니다. 어떤 사람들은 "얕은 복사 문제"때문에 문제를 추가한다고 주장합니다. 이에 대한 나의 주장은 소유 한 RAW 포인터가있는 클래스를 가져서는 안된다는 것입니다. 적절한 스마트 포인터를 사용하면 문제가 사라집니다.

기본 생성자 (다른 생성자가 정의되지 않은 경우)

컴파일러 생성 기본 생성자는 기본 클래스 기본 생성자를 호출 한 다음 각 멤버 기본 생성자를 호출합니다 (선언 된 순서대로).

소멸자 (소멸자가 정의되지 않은 경우)

선언의 역순으로 각 멤버의 소멸자를 호출합니다. 그런 다음 기본 클래스의 소멸자를 호출합니다.

복사 생성자 (복사 생성자가 정의되지 않은 경우)

src 객체를 전달하는 기본 클래스 복사 생성자를 호출합니다. 그런 다음 src 개체 멤버를 복사 할 값으로 사용하여 각 멤버의 복사 생성자를 호출합니다.

할당 연산자

src 객체를 전달하는 기본 클래스 할당 연산자를 호출합니다. 그런 다음 src 개체를 복사 할 값으로 사용하여 각 멤버에서 할당 연산자를 호출합니다.

이동 생성자 (이동 생성자가 정의되지 않은 경우)

src 객체를 전달하는 기본 클래스 이동 생성자를 호출합니다. 그런 다음 src 개체 멤버를 이동할 값으로 사용하여 각 멤버의 이동 생성자를 호출합니다.

이동 할당 연산자

src 객체를 전달하는 기본 클래스 이동 할당 연산자를 호출합니다. 그런 다음 src 개체를 복사 할 값으로 사용하여 각 멤버에서 이동 할당 연산자를 호출합니다.

다음과 같은 클래스를 정의하면 :

struct some_struct: public some_base
{   
    std::string str1;
    int a;
    float b;
    char* c;
    std::string str2;
};

컴파일러가 빌드 할 내용은 다음과 같습니다.

struct some_struct: public some_base
{   
    std::string str1;
    int a;
    float b;
    char* c;
    std::string str2;

    // Conceptually two different versions of the default constructor are built
    // One is for value-initialization the other for zero-initialization
    // The one used depends on how the object is declared.
    //        some_struct* a = new some_struct;     // value-initialized
    //        some_struct* b = new some_struct();   // zero-initialized
    //        some_struct  c;                       // value-initialized
    //        some_struct  d = some_struct();       // zero-initialized
    // Note: Just because there are conceptually two constructors does not mean
    //       there are actually two built.

    // value-initialize version
    some_struct()
        : some_base()            // value-initialize base (if compiler generated)
        , str1()                 // has a normal constructor so just call it
        // PODS not initialized
        , str2()
   {}

    // zero-initialize version
    some_struct()
        : some_base()            // zero-initialize base (if compiler generated)
        , str1()                 // has a normal constructor so just call it.
        , a(0)
        , b(0)
        , c(0)   // 0 is NULL
        , str2()
        // Initialize all padding to zero
   {}

    some_struct(some_struct const& copy)
        : some_base(copy)
        , str1(copy.str1)
        , a(copy.a)
        , b(copy.b)
        , c(copy.c)
        , str2(copy.str2)
    {}

    some_struct& operator=(some_struct const& copy)
    {
        some_base::operator=(copy);
        str1 = copy.str1;
        a    = copy.a;
        b    = copy.b;
        c    = copy.c;
        str2 = copy.str2;
        return *this;
    }

    ~some_struct()
    {}
    // Note the below is pseudo code
    // Also note member destruction happens after user code.
    // In the compiler generated version the user code is empty
        : ~str2()
        // PODs don't have destructor
        , ~str1()
        , ~some_base();
    // End of destructor here.

    // In C++11 we also have Move constructor and move assignment.
    some_struct(some_struct&& copy)
                    //    ^^^^  Notice the double &&
        : some_base(std::move(copy))
        , str1(std::move(copy.str1))
        , a(std::move(copy.a))
        , b(std::move(copy.b))
        , c(std::move(copy.c))
        , str2(std::move(copy.str2))
    {}

    some_struct& operator=(some_struct&& copy)
                               //    ^^^^  Notice the double &&
    {
        some_base::operator=(std::move(copy));
        str1 = std::move(copy.str1);
        a    = std::move(copy.a);
        b    = std::move(copy.b);
        c    = std::move(copy.c);
        str2 = std::move(copy.str2);
        return *this;
    } 
};

C ++에서 구조체는 멤버가 기본적으로 개인 액세스가 아닌 공용으로 설정되는 클래스와 동일합니다.

C ++ 컴파일러는 또한 제공되지 않는 경우 클래스의 다음 특수 멤버를 자동으로 생성합니다.

  • 기본 생성자 -인수 없음, 기본값은 모든 것을 초기화합니다.
  • 복사 생성자 -즉, 동일한 클래스의 다른 객체에 대한 참조를받는 클래스와 이름이 같은 메서드. 모든 값을 복사합니다.
  • 소멸자 -개체가 소멸 될 때 호출됩니다. 기본적으로 아무것도하지 않습니다.
  • 할당 연산자 -하나의 구조체 / 클래스가 다른 구조체에 할당 될 때 호출됩니다. 위의 경우 호출되는 자동 생성 메서드입니다.

이 동작은 C와의 소스 호환성을 유지하기 위해 필요합니다.

C는 연산자를 정의 / 재정의하는 기능을 제공하지 않으므로 일반적으로 구조체는 = 연산자로 복사됩니다.


그러나 그것은 정의되어 있습니다. 표준에서. 연산자 =를 제공하지 않으면 하나가 제공됩니다. 그리고 기본 연산자는 각 멤버 변수를 복사합니다. 그리고 각 구성원을 복사하는 방법을 어떻게 알 수 있습니까? 연산자 = (정의되지 않은 경우 기본적으로 제공됨 ...)를 호출합니다.


할당 연산자 ( operator=)의 C ++ 구조체 또는 클래스에 대한 내재적 생성 기능 중 하나이다.

다음은 암시 적으로 생성 된 4 개의 멤버를 설명하는 참조입니다.
http://www.cs.ucf.edu/~leavens/larchc++manual/lcpp_136.html

간단히 말해서, 암시 적으로 생성 된 멤버는 멤버 별 단순 복사를 수행합니다 . 링크 된 페이지의 긴 버전은 다음과 같습니다.

암시 적으로 생성 된 할당 연산자 사양은 필요한 경우 다음과 같습니다. 사양은 결과가 할당되는 객체 ( self)이고 selfpost-state self"의 추상 값 값이 인수의 추상 값 값과 동일 하다고 말합니다 from.

// @(#)$Id: default_assignment_op.lh,v 1.3 1998/08/27 22:42:13 leavens Exp $
#include "default_interfaces.lh"

T& T::operator = (const T& from) throw();
//@ behavior {
//@   requires assigned(from, any) /\ assigned(from\any, any);
//@   modifies self;
//@   ensures result = self /\ self" = from\any\any;
//@   ensures redundantly assigned(self, post) /\ assigned(self', post);
//           thus
//@   ensures redundantly assigned(result, post) /\ assigned(result', post);
//@ }

컴파일러는 명시 적으로 직접 정의하지 않으면 일부 멤버를 합성합니다. 할당 연산자는 그중 하나입니다. 복사 생성자는 또 다른 것이며 소멸자도 얻습니다. 또한 자체 생성자를 제공하지 않으면 기본 생성자를 얻습니다. 그 외에도 나는 다른 것이 확실하지 않지만 다른 사람이있을 수 있다고 믿습니다 (280Z28에 의해 제공된 답변의 링크는 그렇지 않은 것을 암시하며 지금 어디서 읽었는지 기억할 수 없으므로 아마도 4 일뿐입니다).


구조체는 기본적으로 메모리의 구성 요소를 연결 한 것입니다 (정렬을 위해 가능한 패딩이 내장되어 있음). 하나의 구조체에 다른 구조체의 값을 할당하면 값이 처리됩니다.

참조 URL : https://stackoverflow.com/questions/1575181/why-does-the-operator-work-on-structs-without-having-been-defined

반응형