C ++에서 POD 유형은 무엇입니까?
이 용어 POD 유형을 몇 번 보았습니다. 무슨 뜻이에요?
POD 는 Plain Old Data를 의미합니다. 즉, 생성자, 소멸자 및 가상 멤버 함수가없는 클래스 (키워드 struct
또는 키워드로 정의되었는지 여부에 관계 class
없이)입니다. POD에 대한 Wikipedia의 기사 는 좀 더 자세히 설명하고 다음과 같이 정의합니다.
C ++의 Plain Old Data Structure는 PODS 만 멤버로 포함하고 사용자 정의 소멸자, 사용자 정의 복사 할당 연산자 및 멤버 포인터 유형의 비 정적 멤버가없는 집계 클래스입니다.
C ++ 98 / 03에 대한이 답변 에서 더 자세한 내용을 찾을 수 있습니다 . C ++ 11은 POD를 둘러싼 규칙을 변경하여 크게 완화하여 여기에 후속 답변 이 필요합니다 .
매우 비공식적으로 :
POD는 C ++ 컴파일러가 구조에서 진행되는 "마법"이 없음을 보장하는 유형 (클래스 포함)입니다. 예를 들어 vtable에 대한 숨겨진 포인터, 다른 유형으로 캐스트 될 때 주소에 적용되는 오프셋 ( 적어도 대상의 POD도), 생성자 또는 소멸자. 대략적으로 말하면, 유형은 내장 유형과 이들의 조합 만있는 경우 POD입니다. 그 결과는 C 유형처럼 "동작"하는 것입니다.
덜 비공식적으로 :
int
,char
,wchar_t
,bool
,float
,double
등이며, 포드 있습니다long/short
및signed/unsigned
그 버전.- 포인터 (함수 포인터 및 멤버 포인터 포함)는 POD입니다.
enums
POD입니다- a
const
또는volatile
POD는 POD입니다. class
,struct
또는union
포드의 POD 모든 비 정적 데이터 멤버라는 것을 제공public
하고, 더 기본 클래스없이 생성자 소멸자 또는 가상의 방법이 없다. 정적 멤버는이 규칙에 따라 POD가되는 것을 막지 않습니다. 이 규칙은 C ++ 11에서 변경되었으며 특정 개인 멤버가 허용됩니다. 모든 개인 멤버가있는 클래스가 POD 클래스가 될 수 있습니까?- Wikipedia는 POD가 멤버 포인터 유형의 멤버를 가질 수 없다고 말하는 것은 잘못되었습니다. 또는 오히려 C ++ 98 표현에 맞지만 TC1은 멤버 포인터가 POD임을 명시했습니다.
공식적으로 (C ++ 03 표준) :
3.9 (10) : "산술 유형 (3.9.1), 열거 유형, 포인터 유형 및 멤버 유형에 대한 포인터 (3.9.2) 및 이러한 유형의 cv 규정 버전 (3.9.3)은 집합 적으로 호출자 스칼라 유형입니다. Scalar 유형, POD-struct 유형, POD-union 유형 (9 절), 이러한 유형의 배열 및 이러한 유형의 cv-qualified 버전 (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), 개인 또는 보호 된 비 정적 데이터 멤버 (11 절), 기본 클래스 (10 절)가없는 배열 또는 클래스 (9 절)입니다. 가상 기능이 없습니다 (10.3). "
요컨대, 모든 데이터 유형에 내장 (예이며 int
, char
, float
, long
, unsigned char
, double
POD 데이터 등) 모두 응집. 예, 재귀 적 정의입니다. ;)
더 명확하게 말하면 POD는 우리가 "구조체"라고 부르는 것입니다. 데이터를 저장하는 단위 또는 단위 그룹입니다.
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에서)
참고:
- http://en.cppreference.com/w/cpp/types/is_pod
- http://en.wikipedia.org/wiki/Plain_old_data_structure
- http://en.wikipedia.org/wiki/Plain_Old_C++_Object
- 파일 type_traits
POD (일반 이전 데이터) 객체에는 생성자가없는 기본 유형, 포인터, 공용체, 구조체, 배열 또는 클래스와 같은 데이터 유형 중 하나가 있습니다. 반대로, POD가 아닌 객체는 생성자가 존재하는 객체입니다. POD 객체는 유형에 적합한 크기의 스토리지를 확보 할 때 수명이 시작되고, 객체의 스토리지가 재사용되거나 할당 해제되면 수명이 종료됩니다.
또한 PlainOldData 유형에는 다음이 없어야합니다.
- 가상 기능 (자체 또는 상 속됨)
- 가상 기본 클래스 (직접 또는 간접).
PlainOldData의 느슨한 정의에는 생성자가있는 개체가 포함됩니다. 그러나 가상의 모든 것을 가진 사람들은 제외합니다. PlainOldData 유형의 중요한 문제는 비다 형성이라는 것입니다. 상속은 POD 유형으로 수행 할 수 있지만, 다형성 / 하위 유형이 아닌 ImplementationInheritance (코드 재사용)에 대해서만 수행해야합니다.
일반적인 (엄격하게 정확하지는 않지만) 정의는 PlainOldData 유형이 VeeTable이없는 모든 것입니다.
static_assert
C ++ 11에서 C ++ 17 및 POD 효과 가있는 모든 비 POD 사례의 예
std::is_pod
C ++ 11에 추가되었으므로 지금은 해당 표준을 고려해 보겠습니다.
std::is_pod
https://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 에서 약간의 테스트를 수행 했지만 너무 적습니다. 메인테이너 :이 게시물을 읽으면 이것을 병합하십시오. https://softwareengineering.stackexchange.com/questions/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
// https://stackoverflow.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
}
// Most standard library containers are not POD because they are not trivial,
// which can be seen directly from their interface definition in the standard.
// https://stackoverflow.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>>(), "");
// Some might be though:
// https://stackoverflow.com/questions/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:
// https://stackoverflow.com/questions/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
// https://stackoverflow.com/questions/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
}
테스트 대상 :
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.
POD와 비 POD를 구분해야하는 이유는 무엇입니까?
C++ started its life as an extension of C. While modern C++ is no longer a strict superset of C, people still expect a high level of compatibility between the two.
Roughly speaking, a POD type is a type that is compatible with C and perhaps equally importantly is compatible with certain ABI optimisations.
To be compatible with C, we need to satisfy two constraints.
- The layout must be the same as the corresponding C type.
- The type must be passed to and returned from functions in the same way as the corresponding C type.
Certain C++ features are incompatible with this.
Virtual methods require the compiler to insert one or more pointers to virtual method tables, something that doesn't exist in C.
User-defined copy constructors, move constructors, copy assignments and destructors have implications for parameter passing and returning. Many C ABIs pass and return small parameters in registers, but the references passed to the user defined constructor/assigment/destructor can only work with memory locations.
So there is a need to define what types can be expected to be "C compatible" and what types cannot. C++03 was somewhat over-strict in this regard. C++11 opened things up quite a bit.
The concept of POD and the type trait std::is_pod
will be deprecated in C++20. See this question for further information.
With C++, Plain Old Data doesn't just mean that things like int, char, etc are the only types used. Plain Old Data really means in practice that you can take a struct memcpy it from one location in memory to another and things will work exactly like you would expect (i.e. not blow up). This breaks if your class, or any class your class contains, has as a member that is a pointer or a reference or a class that has a virtual function. Essentially, if pointers have to be involved somewhere, its not Plain Old Data.
참고URL : https://stackoverflow.com/questions/146452/what-are-pod-types-in-c
'code' 카테고리의 다른 글
병합을 완료하지 않았습니다 (MERGE_HEAD가 있음). (0) | 2020.09.28 |
---|---|
git log에 svn log -v와 같은 파일 이름을 표시하는 방법 (0) | 2020.09.28 |
JDK (JNI 공유 라이브러리)를로드하지 못했습니다. (0) | 2020.09.28 |
이벤트를 발생시킨 요소의 ID 가져 오기 (0) | 2020.09.28 |
Node.js를 사용하여 현재 스크립트의 경로를 어떻게 얻습니까? (0) | 2020.09.28 |