c++ - 포인터 - c언어




C++의 POD 타입은 무엇입니까? (6)

나는이 용어 POD 유형을 여러 번 보았습니다. 무슨 뜻이에요?


매우 비공식적으로 :

POD는 C ++ 컴파일러가 구조에 "마법"이 없음을 보장하는 유형 (클래스 포함)입니다. 예를 들어 vtable에 대한 숨겨진 포인터, 다른 유형으로 캐스트 될 때 주소에 적용되는 오프셋 적어도 대상의 POD 인 경우), 생성자 또는 소멸자. 대충 말하면, 타입은 POD로, 그 안에 유일한 것들은 내장 타입과 그 조합입니다. 그 결과 C 유형과 같은 역할을합니다.

덜 비공식적으로 :

  • int , char , wchar_t , bool , float , doublelong/short signed/unsigned 버전과 마찬가지로 POD입니다.
  • 포인터 (함수에 대한 포인터 및 멤버에 대한 포인터 포함)는 POD이며,
  • enums 은 POD입니다.
  • const 또는 volatile POD는 POD입니다.
  • POD의 class , struct 또는 union 은 모든 비 정적 데이터 멤버가 public 이고 기본 클래스가없고 생성자, 소멸자 또는 가상 메서드가없는 경우 POD입니다. 정적 멤버는이 규칙에 따라 POD가되는 것을 멈추지 않습니다. 이 규칙은 C ++ 11에서 변경되었으며 특정 비공개 멤버가 허용됩니다. 모든 비공개 멤버가있는 클래스가 POD 클래스 일 수 있습니까?
  • Wikipedia는 POD가 member-to-member 유형의 멤버를 가질 수 없다고 말하는 것은 잘못입니다. 또는 오히려 C ++ 98 문구가 올바른 것이지만 TC1은 포인터에 대한 포인터가 POD임을 명시했습니다.

공식적으로 (C ++ 03 표준) :

3.9 (10) : "산술 유형 (3.9.1), 열거 유형, 포인터 유형 및 멤버 유형 (3.9.2) 및이 유형의 cv 인증 버전 (3.9.3)에 대한 포인터는 집합 적으로 호출자 스칼라 유형입니다. 유형, POD 구조체 유형, POD 유니온 유형 (9 절), 이러한 유형의 배열 및 이러한 유형의 cv 규정 버전 (3.9.3)을 총칭하여 POD 유형이라고합니다 "

9 (4) : "POD-struct는 non-POD-struct, non-POD-union (또는 그러한 유형의 배열) 또는 참조 유형의 비 정적 데이터 멤버가없고, 사용자 정의 클래스가없는 집계 클래스입니다. 마찬가지로 POD-union은 non-POD-struct, non-POD-union (또는 그러한 유형의 배열) 또는 참조 유형의 비 정적 데이터 멤버가없는 집계 유니온이며, 사용자 정의 복사 연산자 및 사용자 정의 소멸자가 없습니다.

8.5.1 (1) : "집계는 사용자가 선언 한 구성 자 (12.1)가없는 배열 또는 클래스 (9 절), 비공개 또는 보호 된 비 정적 데이터 멤버가 없음 (11 절), 기본 클래스가 없음 (10 절) 가상 기능은 없다 (10.3). "


C ++에서 Plain Old Data는 int, char 등이 유일한 유형이라는 것을 의미하지 않습니다. Plain Old Data는 실제로 memcpy 구조체를 메모리의 한 위치에서 다른 위치로 옮길 수 있다는 것을 의미합니다. 예상대로 작동합니다 (즉, 폭발하지 않음). 클래스 또는 클래스에 포함 된 클래스에 포인터, 참조 또는 가상 함수가있는 클래스 인 멤버가있는 경우이 동작이 중단됩니다. 본질적으로, 포인터가 어딘가에 관련되어야한다면, 포인터는 기존의 낡은 데이터가 아닙니다.


POD (일반 오래된 데이터) 객체에는 생성자가없는 기본 유형, 포인터, 공용체, 구조체, 배열 또는 클래스 중 하나의 데이터 유형이 있습니다. 반대로 비 POD 객체는 생성자가 존재하는 객체입니다. POD 객체는 유형에 맞는 크기의 저장 공간을 확보하고 객체의 저장 공간을 다시 사용하거나 할당을 해제 할 때 수명이 끝나면 수명이 시작됩니다.

PlainOldData 유형에도 다음 중 하나가 없어야합니다.

  • 가상 함수 (자체 함수 또는 상속 된 함수)
  • 가상 기본 클래스 (직접 또는 간접).

PlainOldData의 느슨한 정의에는 생성자가있는 객체가 포함됩니다. 가상의 것을 가진 사람들은 제외합니다. PlainOldData 형식의 중요한 문제는 해당 형식이 비 다형성이라는 점입니다. 상속은 POD 유형을 사용하여 수행 할 수 있지만 다형성 / 하위 유형이 아닌 ImplementationInheritance (코드 재사용)에서만 수행해야합니다.

공통적 인 (그러나 정확하지는 않지만) 정의는 PlainOldData 유형이 VeeTable이없는 것으로 정의됩니다.


POD 및 type trait std::is_pod 의 개념은 C ++에서 더 이상 사용되지 않습니다. 자세한 내용은 this 질문을 참조하십시오.


POD일반 올드 데이터를 나타냅니다. 즉, 생성자, 소멸자 및 가상 멤버 함수가없는 class 키워드 struct 또는 키워드 class 정의되었는지 여부)입니다. POD에 관한 Wikipedia의 기사 는 좀 더 자세히 설명하고 다음과 같이 정의합니다.

C ++의 일반 오래된 데이터 구조는 멤버로 PODS 만 포함하고 사용자 정의 소멸자가없고 사용자 정의 복사본 할당 연산자가없고 멤버 유형 포인터 유형의 정적 멤버가없는 집계 클래스입니다.

보다 자세한 내용은 C ++ 98 / 03에 대한이 답변 에서 찾을 수 있습니다. C ++ 11은 POD를 둘러싼 규칙을 변경하여 크게 완화했습니다. 따라서 여기에서 후속 답변 이 필요합니다 .


C ++ 11에서 C ++ 17까지의 static_assert 가있는 가능한 모든 비 POD 사례

std::is_pod 가 C ++ 11에 추가되었으므로 표준을 앞으로 고려해 보겠습니다.

std::is_pod 는 https://.com/a/48435532/895245 에서 언급 한 것처럼 C ++ 20에서 제거 될 것이므로 대체물에 대한 지원이 업데이트되면이를 업데이트 해 봅시다.

표준이 진화함에 따라 POD 제한이 점점 완화되면서 나는 모든 휴식을 모범으로 삼고 자합니다.

libstdc ++는 https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc 에서 약간의 테스트를 https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc 습니다. 너무 작은. 유지 관리자 :이 게시물을 읽으면이 부분을 병합하십시오. 내가 언급 한 모든 프로젝트를 확인하는 것은 게으른 일이다. https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers 누군가가 그러한 프로젝트를 만들었다면 그녀는 유명해질 것입니다.

귀하의 편집, C + + 전문가와 모든 누락 된 TODOs를 죽일 도와주세요.

#include <type_traits>
#include <vector>

int main() {
/* POD restrictions have become more and more relaxed as the standard evolved.
 *
 * std::is_pod was added in C++11, so let's consider that standard onwards for now.
 */
#if __cplusplus >= 201103L
    /* Non-POD examples. Let's just walk all non-recursive non-POD branches of cppreference. */
    {
        /* Non-trivial implies non-POD.
         * https://en.cppreference.com/w/cpp/named_req/TrivialType
         */
        {
            /* Has one or more default constructors, all of which are either
             * trivial or deleted, and at least one of which is not deleted.
             */
            {
                /* Not trivial because we removed the default constructor
                * by using our own custom non-default constructor.
                */
                {
                    struct C {
                        C(int i) {}
                    };
                    static_assert(std::is_trivially_copyable<C>());
                    static_assert(!std::is_trivial<C>());
                    static_assert(!std::is_pod<C>());
                }

                /* No, this is not a default trivial constructor either:
                 * https://en.cppreference.com/w/cpp/language/default_constructor
                 *
                 * The constructor is not user-provided (i.e., is implicitly-defined or
                 * defaulted on its first declaration)
                 */
                {
                    struct C {
                        C() {}
                    };
                    static_assert(std::is_trivially_copyable<C>());
                    static_assert(!std::is_trivial<C>());
                    static_assert(!std::is_pod<C>());
                }
            }

            /* Not trivial because not trivially copyable. */
            {
                struct C {
                    C(C& c) {}
                };
                static_assert(!std::is_trivially_copyable<C>());
                static_assert(!std::is_trivial<C>());
                static_assert(!std::is_pod<C>());
            }
        }

        /* Non-standard layout implies non-POD.
         * https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
         */
        {
            /* Non static members with different access control:
             * i is public and j is private.
             */
            {
                struct C {
                    public:
                        int i;
                    private:
                        int j;
                };
                static_assert(!std::is_standard_layout<C>());
                static_assert(!std::is_pod<C>());
            }

            /* virtual function */
            {
                struct C {
                    virtual void f() = 0;
                };
                static_assert(!std::is_standard_layout<C>());
                static_assert(!std::is_pod<C>());
            }

            /* Non-static member that is reference. */
            {
                struct C {
                    int &i;
                };
                static_assert(!std::is_standard_layout<C>());
                static_assert(!std::is_pod<C>());
            }

            /* Neither:
             *
             * - has no base classes with non-static data members, or
             * - has no non-static data members in the most derived class
             *   and at most one base class with non-static data members
             */
            {
                /* Non POD because has two base classes with non-static data members. */
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {
                        int j;
                    };
                    struct C : Base1, Base2 {};
                    static_assert(!std::is_standard_layout<C>());
                    static_assert(!std::is_pod<C>());
                }

                /* POD: has just one base class with non-static member. */
                {
                    struct Base1 {
                        int i;
                    };
                    struct C : Base1 {};
                    static_assert(std::is_standard_layout<C>());
                    static_assert(std::is_pod<C>());
                }

                /* Just one base class with non-static member: Base1, Base2 has none. */
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {};
                    struct C : Base1, Base2 {};
                    static_assert(std::is_standard_layout<C>());
                    static_assert(std::is_pod<C>());
                }
            }

            /* Base classes of the same type as the first non-static data member.
             * TODO failing on GCC 8.1 -std=c++11, 14 and 17.
             */
            {
                struct C {};
                struct D : C {
                    C c;
                };
                //static_assert(!std::is_standard_layout<C>());
                //static_assert(!std::is_pod<C>());
            };

            /* C++14 standard layout new rules, yay! */
            {
                /* Has two (possibly indirect) base class subobjects of the same type.
                 * Here C has two base classes which are indirectly "Base".
                 *
                 * TODO failing on GCC 8.1 -std=c++11, 14 and 17.
                 * even though the example was copy pasted from cppreference.
                 */
                {
                    struct Q {};
                    struct S : Q { };
                    struct T : Q { };
                    struct U : S, T { };  // not a standard-layout class: two base class subobjects of type Q
                    //static_assert(!std::is_standard_layout<U>());
                    //static_assert(!std::is_pod<U>());
                }

                /* Has all non-static data members and bit-fields declared in the same class
                 * (either all in the derived or all in some base).
                 */
                {
                    struct Base { int i; };
                    struct Middle : Base {};
                    struct C : Middle { int j; };
                    static_assert(!std::is_standard_layout<C>());
                    static_assert(!std::is_pod<C>());
                }

                /* None of the base class subobjects has the same type as
                 * for non-union types, as the first non-static data member
                 *
                 * TODO: similar to the C++11 for which we could not make a proper example,
                 * but with recursivity added.
                 */

                /* TODO come up with an example that is POD in C++14 but not in C++11. */
            }
        }
    }

    /* POD examples. Everything that does not fall in the non-POD examples. */
    {
        /* Can't get more POD than this. */
        {
            struct C {};
            static_assert(std::is_pod<C>());
        }

        /* Private member: became POD in C++11
         * https://.com/questions/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944#4762944
         */
        {
            struct C {
                private:
                    int i;
            };
#if __cplusplus >= 201103L
            static_assert(std::is_pod<C>());
#else
            static_assert(!std::is_pod<C>());
#endif
        }

        /* Standard library containers are not, for the most part (all?),
         * POD because they are not trivial, which can be seen directly from their
         * interface definition in the standard.
         * https://.com/questions/27165436/pod-implications-for-a-struct-which-holds-an-standard-library-container
         */
        {
            static_assert(!std::is_pod<std::vector<int>>());
            static_assert(!std::is_trivially_copyable<std::vector<int>>());
        }

        /* Array of POD is POD. */
        {
            struct C {};
            static_assert(std::is_pod<C>());
            static_assert(std::is_pod<C[]>());
        }
    }
#endif
}

GitHub 업스트림 .

테스트 대상 :

for std in 11 14 17; do echo $std; g++-8 -std=c++$std pod.cpp; done

우분투 18.04.

사람에게 알려진 모든 POD 효과 목록

이미 목록이 있습니다 : https://.com/a/4178176/895245 하지만 적어도 예제로 예제 나 링크가 모두 필요하면 멀리 편집하십시오 :





c++-faq