C ++의 POD 유형은 무엇입니까?


977

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



5
허용 된 답변에 대한 토론 은 chat.stackoverflow.com/transcript/message/213026#213026 및 다음 날의 메시지 를 참조하십시오
Johannes Schaub-litb


@ paxos1977 : "솔루션"(현재 Hewgill의 답변) 선택을 변경하여 근본적으로 잘못된 답변으로 끝나는 Google 직원을 오도하지 않도록하십시오.
건배와 hth. -Alf

우리는 c 스타일 문자열이 POD 유형이 아니라고 결론을 내 렸습니다 .1) 포인터가 문자열 데이터와 연속적이지 않으며 2.) 문자열을 POD 유형으로 만들려면 유형을 확인해야합니다. POD 유형의 사전 정의 된 크기 내에 무 항자 문자가 포함되어있어 정의되지 않은 동작이 발생합니다.

답변:


694

PODPlain Old Data , 즉 생성자, 소멸자 및 가상 멤버 함수가없는 클래스 (키워드 struct또는 키워드로 정의 된 클래스 class)를 나타냅니다. POD에 관한 Wikipedia의 기사 는 좀 더 자세히 설명하고 다음과 같이 정의합니다.

C ++의 Plain Old Data Structure는 PODS 만 멤버로 포함하고 사용자 정의 소멸자, 사용자 정의 사본 할당 연산자 및 포인터 대 멤버 유형의 비 정적 멤버가없는 집계 클래스입니다.

C ++ 98 / 03에 대한이 답변 에서 더 자세한 내용을 찾을 수 있습니다 . C ++ 11은 POD와 관련된 규칙을 변경하여 크게 완화 하여 후속 답변필요합니다 .


34
차이가 있습니다. 내장 유형은 "기본 제공"언어 기본 요소입니다. POD 유형은 이러한 유형과 이들 (및 다른 POD)의 집계입니다.
Adam Wright

59
POD 유형에는 비 POD 유형이 아닌 특성이 있습니다. 예를 들어 전역, const, POD 유형 구조체가있는 경우 중괄호 표기법으로 내용을 초기화 할 수 있으며 읽기 전용 메모리에 저장되며 초기화하기 위해 코드를 생성 할 필요가 없습니다 (생성자 또는 기타). 프로그램 이미지의 일부이기 때문입니다. 이것은 종종 RAM, ROM 또는 플래시에 대한 제약이있는 임베디드 사용자에게 중요합니다.
Mike DeSimone

34
C ++ 11에서는 std :: is_pod <MyType> ()을 수행하여 MyType이 POD인지 여부를 알 수 있습니다.
allyourcode

7
Bjarne Stroustrup의 C ++ 성능 기술 보고서에 따르면 C ++ 표준은 POD를 " 레이아웃, 초기화 및 memcpy로 복사하는 기능에서 C의 동등한 데이터 유형과 호환되는 데이터 유형 "으로 설명합니다. 아마도 POD 유형과 POD 구조를 구별해야합니다.
user34660

6
−1 2016 년 8 월 16 일 현재이 답변은 여전히 ​​근본적으로 잘못되고 잘못된 것입니다. POD 유형은 클래스 유형으로 제한되지 않습니다.
건배와 hth. -Alf

352

매우 비공식적으로 :

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

비공식적으로 :

  • int, char, wchar_t, bool, float, double등이며, 포드 있습니다 long/shortsigned/unsigned그 버전.
  • 포인터 (함수 대 함수 및 포인터 대 멤버 포함)는 POD입니다.
  • enums 포드입니다
  • a const또는 volatilePOD는 POD입니다.
  • class, struct또는 union포드의 POD 모든 비 정적 데이터 멤버라는 것을 제공 public하고, 더 기본 클래스없이 생성자 소멸자 또는 가상의 방법이 없다. 정적 멤버는이 규칙에 따라 POD가되는 것을 멈추지 않습니다. 이 규칙은 C ++ 11에서 변경되었으며 특정 개인 구성원이 허용됩니다. 모든 개인 구성원이있는 클래스가 POD 클래스가 될 수 있습니까?
  • 위키 백과는 POD가 포인터 대 멤버 유형의 멤버를 가질 수 없다고 말하는 것은 잘못입니다. 또는 오히려 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 연합은 non-POD-struct, non-POD-union (또는 이러한 유형의 배열) 유형의 비 정적 데이터 멤버 또는 참조가없는 집계 통합입니다. 사용자 정의 복사 연산자와 사용자 정의 소멸자가 없습니다.

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


3
공식 / 약식이 있습니다. 경험 법칙을 추가 할 수 있습니다. 내장 유형 및 이와 유사한 유형의 내장 유형 및 집계 정확한 정의를 얻기 위해 지식을 쉽게 사용할 수 있도록해야합니다.
Martin York

1
" 다른 유형으로 캐스트 할 때 오프셋"비트가 약간 잘못되었습니다 . 이러한 오프셋은 기본 또는 파생 클래스로 캐스팅 할 때 적용됩니다. 따라서 POD 기본 클래스 포인터에서 비 POD 파생 클래스로 캐스트해도 여전히 조정이 발생할 수 있습니다.
MSalters

1
@Steve Jessop : 왜 POD와 비 POD를 구별해야합니까?
Lazer

6
@Lazer : "POD는 어떻게 작동합니까?" "POD의 의미는 무엇입니까?" 요약하면 차이점은 초기화 (따라서 객체 복제에 memcpy 사용), 해당 컴파일러의 C struct 레이아웃과의 호환성, 포인터 업 / 다운 캐스팅과 관련이 있습니다. POD는 "C 유형과 유사하게 작동"하고 비 POD는 그렇게 보장하지 않습니다. 따라서 유형이 C 구조체처럼 이식 가능하게 작동하려면 POD인지 확인해야하므로 차이를 알아야합니다.
Steve Jessop

4
@ muntoo : 실제로 Wikipedia의 오래된 정보를 인용하는 답변에 대해 언급하고있었습니다. 나는 그 대답을 편집 할 수 있다고 생각하지만, 내가 옳다고 생각하더라도 다른 사람들의 대답을 편집하여 내 의견에 동의하면 문제가 발생합니다.
Steve Jessop

20

평범한 오래된 데이터

요컨대, 모든 데이터 유형에 내장 (예이며 int, char, float, long, unsigned char, doublePOD 데이터 등) 모두 응집. 예, 재귀 적 정의입니다. ;)

더 명확하게 말하면, POD는 데이터를 저장하는 단위 또는 단위 그룹 인 "구조체"라고 부릅니다.


12
우리는 때때로 그들을 '구조체'라고 부르는 것이 사실입니다. 그러나 구조체는 반드시 POD 유형이 아니기 때문에 항상 그렇게하는 것은 잘못입니다.
Steve Jessop

6
분명히 ... 구조체와 클래스는 거의 동일하지만 "비즈니스"에서는 일반적으로
ctor

2
나를 위해 구조체 키워드를 클래스 키워드와 동일하게 만들거나 가까이하는 것은 C ++이 잘못되었습니다 : struct는 클래스에 공개 기본 액세스 만 추가합니다. 나는 C와 같은 구조체를 만드는 것이 더 간단했고 우리는 c ++의 0 일에 POD를 가질 것입니다.
user1708042

ugasoft : 귀하의 답변이 오해의 소지가있을 수 있습니다. 귀하의 의견은 표준이 아닌 실제와 같이 누락 된 세부 사항을 설명했습니다. 우와, 8 년여, 여기 있니? ;-)
hauron

문자열 길이는 먼저 문자열 길이를 결정하지 않고 memcpy로 복사 할 수 없기 때문에 예외입니다.

12

POD (PlainOldData)는 원시 데이터 일 뿐이므로 필요하지 않습니다.

  • 건설 될
  • 파괴되고
  • 사용자 정의 연산자가 있어야합니다.
  • 가상 기능이 없어야합니다.
  • 연산자를 재정의해서는 안됩니다.

POD가 있는지 확인하는 방법? 글쎄, 그에 대한 구조체가 있습니다 std::is_pod:

namespace std {
// Could use is_standard_layout && is_trivial instead of the builtin.
template<typename _Tp>
  struct is_pod
  : public integral_constant<bool, __is_pod(_Tp)>
  { };
}

(헤더 type_traits에서)


참고:


2
POD 유형에 멤버 함수 또는 과부하 된 연산자가있을 수 있습니다. (그러나 가상 멤버 기능이 없을 수도 있습니다.)
Colin D Bennett

@ColinDBennett 그래, 맞아. 혼란을 드려 죄송합니다. 응답자의 안팎으로 편집했습니다.
набиячлэвэли

10

POD (plain old data) 객체에는 생성자가없는 기본 유형, 포인터, 공용체, 구조체, 배열 또는 클래스와 같은 데이터 유형 중 하나가 있습니다. 반대로, 비 POD 객체는 생성자가 존재하는 객체입니다. POD 오브젝트는 유형에 적합한 크기의 스토리지를 확보 할 때 수명이 시작되고 오브젝트의 스토리지가 재사용되거나 할당이 해제되면 수명이 종료됩니다.

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

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

PlainOldData의 느슨한 정의에는 생성자가있는 객체가 포함됩니다. 가상의 물건은 제외합니다. PlainOldData 형식의 중요한 문제는 다형성이 아니라는 것입니다. 상속은 POD 유형으로 수행 할 수 있지만 다형성 / 서브 타이핑이 아닌 ImplementationInheritance (코드 재사용)에 대해서만 수행해야합니다.

(정확히 정확하지는 않지만) 일반적인 정의는 PlainOldData 유형이 VeeTable이없는 것입니다.


유어 답변은 매우 좋지만이 질문은 8 년 전에 답변을 받았으며 몇 가지 다른 좋은 답변도 받아 들였습니다. 아직 답변되지 않은 질문에 답하기 위해 지식을 사용하면 SO에 더 많은 기여를 할 수 있습니다.)))
mvidelgauz

10

왜 POD와 비 POD를 구별해야합니까?

C ++는 C의 확장으로 수명을 시작했습니다. 현대 C ++은 더 이상 C의 엄격한 수퍼 세트가 아니지만 사람들은 여전히이 둘 사이의 높은 호환성을 기대합니다.

대략적으로 말하면, POD 유형은 C와 호환되는 유형이며 아마도 ABI 최적화와 호환되는 것도 마찬가지로 중요합니다.

C와 호환 되려면 두 가지 제약 조건을 만족해야합니다.

  1. 레이아웃은 해당 C 유형과 동일해야합니다.
  2. 유형은 해당 C 유형과 동일한 방식으로 함수에 전달되고 함수에서 리턴되어야합니다.

특정 C ++ 기능은이 기능과 호환되지 않습니다.

가상 메소드에는 컴파일러가 C에 존재하지 않는 가상 메소드 테이블에 대한 하나 이상의 포인터를 삽입해야합니다.

사용자 정의 복사 생성자, 이동 생성자, 복사 할당 및 소멸자는 매개 변수 전달 및 반환과 관련이 있습니다. 많은 C ABI가 레지스터에서 작은 매개 변수를 전달하고 반환하지만 사용자 정의 생성자 / 어시스트 / 소멸자에 전달 된 참조는 메모리 위치에서만 작동 할 수 있습니다.

따라서 "C 호환 가능"으로 예상 할 수있는 유형과 불가능한 유형을 정의해야합니다. C ++ 03은 이와 관련하여 다소 엄격했습니다. 사용자 정의 생성자는 내장 생성자를 비활성화하고 다시 추가하려고하면 사용자 정의가 생성되어 유형이 비 포드가됩니다. C ++ 11은 사용자가 내장 생성자를 다시 소개 할 수있게함으로써 상당히 많은 것을 열었습니다.


8

static_assertC ++ 11에서 C ++ 17 및 POD 효과 가있는 모든 비 POD 사례의 예

std::is_pod C ++ 11에 추가되었으므로 이제 그 표준을 고려해 봅시다.

std::is_podhttps://stackoverflow.com/a/48435532/895245에 언급 된대로 C ++ 20에서 제거됩니다 . 교체를위한 지원이 도착할 때이를 업데이트하겠습니다.

표준이 발전함에 따라 POD 제한이 점점 완화되었습니다. 나는 ifdef를 통해 예제에서 모든 이완을 다루는 것을 목표로합니다.

libstdc ++는 https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc 에서 약간의 테스트를 거쳤 지만 너무 작습니다. 관리자 :이 게시물을 읽으면이를 병합하십시오. /software/199708/is-there-a-compliance-test-for-c-compilers에 언급 된 모든 C ++ 테스트 스위트 프로젝트를 확인하는 것이 게으르다.

#include <type_traits>
#include <array>
#include <vector>

int main() {
#if __cplusplus >= 201103L
    // # Not POD
    //
    // 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) {}
                    };
                    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&) {}
                };
                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>(), "");
                }

                // These have the same access control.
                {
                    struct C {
                        private:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");

                    struct D {
                        public:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<D>(), "");
                    static_assert(std::is_pod<D>(), "");
                }
            }

            // 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
    //
    // POD examples. Everything that does not fall neatly in the non-POD examples.
    {
        // Can't get more POD than this.
        {
            struct C {};
            static_assert(std::is_pod<C>(), "");
            static_assert(std::is_pod<int>(), "");
        }

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

        // Private member: became POD in C++11
        // /programming/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
        }

        // Most standard library containers are not POD because they are not trivial,
        // which can be seen directly from their interface definition in the standard.
        // /programming/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>>(), "");
            // Some might be though:
            // /programming/3674247/is-stdarrayt-s-guaranteed-to-be-pod-if-t-is-pod
            static_assert(std::is_pod<std::array<int, 1>>(), "");
        }
    }

    // # POD effects
    //
    // Now let's verify what effects does PODness have.
    //
    // Note that this is not easy to do automatically, since many of the
    // failures are undefined behaviour.
    //
    // A good initial list can be found at:
    // /programming/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special/4178176#4178176
    {
        struct Pod {
            uint32_t i;
            uint64_t j;
        };
        static_assert(std::is_pod<Pod>(), "");

        struct NotPod {
            NotPod(uint32_t i, uint64_t j) : i(i), j(j) {}
            uint32_t i;
            uint64_t j;
        };
        static_assert(!std::is_pod<NotPod>(), "");

        // __attribute__((packed)) only works for POD, and is ignored for non-POD, and emits a warning
        // /programming/35152877/ignoring-packed-attribute-because-of-unpacked-non-pod-field/52986680#52986680
        {
            struct C {
                int i;
            };

            struct D : C {
                int j;
            };

            struct E {
                D d;
            } /*__attribute__((packed))*/;

            static_assert(std::is_pod<C>(), "");
            static_assert(!std::is_pod<D>(), "");
            static_assert(!std::is_pod<E>(), "");
        }
    }
#endif
}

GitHub의 상류 .

로 테스트 :

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

Ubuntu 18.04, GCC 8.2.0에서.


4

POD의 개념과 유형 특성 std::is_pod은 C ++ 20에서 더 이상 사용되지 않습니다. 자세한 내용은 질문을 참조하십시오 .


-7

C ++에서 Plain Old Data는 int, char 등과 같은 것이 유일하게 사용되는 유형을 의미하지는 않습니다. Plain Old Data는 실제로 메모리의 한 위치에서 다른 위치로 struct memcpy를 취할 수 있으며 예상대로 작동합니다 (예 : 폭파하지 않음). 클래스 또는 클래스에 포함 된 클래스에 포인터 또는 참조 인 멤버 또는 가상 함수가있는 클래스가 있으면 중단됩니다. 본질적으로 포인터가 어딘가에 관련되어야하는 경우 일반 오래된 데이터가 아닙니다.


6
POD 구조체에는 포인터가 허용됩니다. 참조는 없습니다.
j_random_hacker

1
Passant가 여기에 없습니다.
icbytes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.