C ++ 'da POD türleri nelerdir?


977

Bu terim POD tipi ile birkaç kez karşılaştım.
Bunun anlamı ne?



5
lütfen chat.stackoverflow.com/transcript/message/213026#213026 ve kabul edilen cevap hakkında tartışma için ertesi günün mesajlarına bakın
Johannes Schaub - litb


@ paxos1977: Lütfen "çözüm" seçiminizi (şu anda Hewgill'in cevabı) değiştirin, böylece temelde yanlış bir cevap burada bulunan Google çalışanlarını yanlış yönlendirmez.
Şerefe ve s. - Alf

Bir c-stil dizesinin POD tipi DEĞİL olduğu sonucuna vardık, çünkü 1.) işaretçi dize verileriyle bitişik değildir ve 2.) bir dizeyi POD tipi yapmak için, türün içinde tanımlanmamış davranışa yol açan, POD tipinin önceden tanımlanmış boyutu içinde sıfır terimli bir karakter vardı.

Yanıtlar:


694

POD , Düz Eski Veriler anlamına gelir - yani, oluşturucular, yıkıcılar ve sanal üye işlevleri olmayan bir sınıf (anahtar kelime structveya anahtar kelime ile tanımlanmış olsun class). Wikipedia'nın POD makalesi biraz daha ayrıntıya giriyor ve şöyle tanımlıyor:

C ++ 'da Düz Eski Veri Yapısı, yalnızca PODS'yi üye olarak içeren, kullanıcı tanımlı bir yıkıcıya, kullanıcı tanımlı kopya atama operatörüne ve işaretçi-üye türünün statik olmayan üyelerine sahip olmayan bir toplu sınıftır.

C ++ 98/03 için bu yanıtta daha fazla ayrıntı bulunabilir . C ++ 11, POD'u çevreleyen kuralları değiştirdi, onları büyük ölçüde gevşetti, bu yüzden burada bir takip cevabı gerektirdi .


34
Bir fark var. İçsel tipler "yerleşik" dil ilkelleri. POD türleri bunlar, artı bunların (ve diğer POD'ların) kümeleridir.
Adam Wright

59
POD tipleri, POD olmayan tiplerin sahip olmadığı özelliklere sahiptir. Örneğin, global, const, POD tipi bir yapınız varsa, içeriğini küme ayracı notasyonu ile başlatabilirsiniz, salt okunur belleğe yerleştirebilirsiniz ve başlatmak için herhangi bir kod üretilmesine gerek yoktur (kurucu veya başka türlü), çünkü program görüntüsünün bir parçası. Bu, genellikle RAM, ROM veya Flash üzerinde sıkı kısıtlamaları olan gömülü kişiler için önemlidir.
Mike DeSimone

34
C ++ 11'de, MyType'ın POD olup olmadığını söylemek için std :: is_pod <MyType> () yapabilirsiniz.
allyourcode

7
Bjarne Stroustrup'un C ++ Performansına İlişkin Teknik Raporu , C ++ standardının bir POD'u " mizanpaj, başlatma ve memcpy ile kopyalanabilme yeteneği bakımından C'deki eşdeğer veri türüyle uyumlu bir veri türü " olarak tanımladığını belirtir . Belki de POD tipi ile POD yapısı arasında bir ayrım yapılmalıdır.
user34660

6
Answer1 Bu cevap, 16 Ağustos 2016 itibarıyla hala temelde yanlış ve yanıltıcıdır: POD türleri sınıf türleri ile sınırlı değildir.
Şerefe ve s. - Alf

352

Gayri resmi olarak:

POD, C ++ derleyicisinin yapıda herhangi bir "sihirli" olmayacağını garanti ettiği bir türdür (sınıflar dahil): örneğin, tablolara gizli işaretçiler, diğer türlere kullanıldığında adrese uygulanan ofsetler ( en azından hedefin POD'u da varsa), yapıcılar veya yıkıcılar. Kabaca söylemek gerekirse, bir tür içindeki tek şey yerleşik türler ve bunların kombinasyonları olduğunda bir POD'dur. Sonuç, bir C tipi "gibi davranan" bir şeydir.

Daha az gayri resmi:

  • int, char, wchar_t, bool, float, doubleGibidir, POD'lar vardır long/shortve signed/unsignedbunların sürümleri.
  • işaretçiler (işaretçi-işlev ve işaretçi-üye dahil) POD'lardır,
  • enums POD'lar
  • a constveya volatilePOD, bir POD'dur.
  • Bir class, structya unionPODs bir POD tüm statik olmayan veri üyeleri koşuluyla olduğunu publicve hiçbir temel sınıf ve hiçbir kurucular, yıkıcı veya sanal yöntemleri vardır. Statik üyeler, bu kural uyarınca bir şeyin POD olmasını durdurmazlar. Bu kural C ++ 11'de değişmiştir ve bazı özel üyelere izin verilir: Tüm özel üyeleri olan bir sınıf POD sınıfı olabilir mi?
  • Wikipedia, bir POD'un işaretçi-üye tipinde üyelere sahip olamayacağını söylemek yanlıştır. Daha doğrusu, C ++ 98 ifadeleri için doğrudur, ancak TC1, üyeye işaretçilerin POD olduğunu açıkça belirtti.

Resmi olarak (C ++ 03 Standardı):

3.9 (10): "Aritmetik tipler (3.9.1), numaralandırma tipleri, işaretçi tipleri ve üye tiplerine işaretçi (3.9.2) ve bu tiplerin cv nitelikli versiyonları (3.9.3) toplu olarak arayan skaler tipleridir. türleri, POD-yapı türleri, POD-birleştirme türleri (madde 9), bu türlerin dizileri ve bu türlerin cv nitelikli sürümleri (3.9.3) toplu olarak POD türleri olarak adlandırılır "

9 (4): "POD-yapı, POD-yapı olmayan, POD-birliği olmayan (veya bu tür bir dizi) veya başvuru türünde statik olmayan veri üyelerine sahip olmayan ve kullanıcı- kopya operatörünü tanımlayın ve kullanıcı tanımlı yıkıcı yok: Benzer şekilde POD-birliği, POD-yapı olmayan, POD-birliği olmayan (veya bu tür bir dizi) veya başvuru türünde statik olmayan veri üyelerine sahip olmayan bir toplu birleşmedir, kullanıcı tanımlı kopya operatörü ve kullanıcı tanımlı yıkıcı içermez.

8.5.1 (1): "Toplam, kullanıcı tarafından bildirilen kurucuları (12.1), özel veya korumalı statik olmayan veri üyeleri (madde 11), temel sınıflar (madde 10) içermeyen bir dizi veya sınıftır (madde 9). ve sanal işlev yok (10.3). "


3
Resmi / daha az resmi var. Temel kural ekleyebilirsiniz. Dahili türler ve kümeler Dahili türler (veya bunun gibi bir şey). Kesin tanımlamaya ek olarak, bilginin kullanımını kolaylaştırmalıyız.
Martin York

1
" Başka bir türe cast_to zaman ofset" bit biraz yanlış . Bu ofsetler bir tabana veya türetilmiş sınıfa döküm yaparken uygulanır. Bu nedenle, bir POD temel sınıf işaretçisinden POD türetilmemiş bir sınıfa yayın yaparsanız, yine de bir ayarlama ile karşılaşabilirsiniz.
MSalters

1
@Steve Jessop: Neden POD'lar ile POD olmayanlar arasında ayrım yapmamız gerekiyor?
Lazer

6
@Lazer: Bu başka bir soru, "POD'lar nasıl davranıyor?" "POD ne anlama geliyor?" Özet olarak fark, başlatma (bu nedenle nesneleri kopyalamak için memcpy kullanımı), o derleyici için C yapı düzeniyle uyumluluk ve işaretçi yukarı ve aşağı döküm ile ilgilidir. POD'lar "C tipi gibi davranır", POD olmayanların bunu yapması garanti edilmez. Dolayısıyla, türünüzün taşınabilir bir şekilde bir C yapısı gibi davranmasını istiyorsanız, bunun POD olduğundan emin olmalısınız, bu yüzden farkı bilmeniz gerekir.
Steve Jessop

4
@muntoo: Gerçekten, Wikipedia'dan güncel olmayan bilgileri alıntılayan cevap hakkında yorum yapıyordum. Sanırım bu cevabı düzenleyebilirim, ama benim hakkımda ne kadar doğru olduğumu düşünsem de, başkalarının cevabını benimkiyle aynı fikirde olmak üzere düzenlersem sorun duyarım.
Steve Jessop

20

Düz Eski Veriler

Kısacası, tüm veri tipleri dahili (örn olduğunu int, char, float, long, unsigned char, doublePOD veri, vb) ve tüm toplanma. Evet, özyinelemeli bir tanım. ;)

Daha açık olmak gerekirse, POD "yapı" dediğimiz şeydir: sadece veri depolayan bir birim veya birim grubu.


12
Bazen onlara 'yapı' dediğimiz doğrudur. Bununla birlikte, her zaman bunu yapmak yanlıştır, çünkü bir yapı mutlaka POD tipi değildir.
Steve Jessop

6
Açıkçası ... yapı ve sınıf neredeyse eşdeğerdir, ancak "iş" te "yapı" olarak adlandırırız, genellikle değer semantikleri olan, genellikle
ctor

2
Benim için yapı sınıf anahtar kelimesi ile aynı veya yakın yapmak C ++ yanlıştı: struct sadece sınıfa genel varsayılan erişim ekler. C benzeri yapılar yapmak daha basitti ve c ++ 'ın 0. gününde POD'larımız olurdu.
user1708042

ugasoft: cevabınız yanıltıcı olabilir - yorumunuz standarttan ziyade pratikte böyle kullanıldığı eksik detayını açıkladı. Whoa, 8 yıl, sen burada mısın? ;-)
hauron

Bir dize dışında, önce dize uzunluğunu belirlemeden memcpy ile kopyalayamazsınız.

12

Anladığım kadarıyla POD (PlainOldData) sadece ham bir veri - gerek yok:

  • inşa edilecek,
  • yok edilmek,
  • özel işleçlere sahip olmak.
  • Sanal işlevlere sahip olmamalı,
  • ve operatörleri geçersiz kılmamalıdır.

Bir şeyin POD olup olmadığını nasıl kontrol edebilirim? Bunun için bir yapı var 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 başlıktan)


Referans:


2
Yanlış, bir POD türü üye işlevlerine veya aşırı yüklenmiş işleçlere sahip olabilir. (Ancak sanal üye işlevleri olmayabilir.)
Colin D Bennett

@ColinDBennett Evet, bu doğru. Karışıklık için özür dilerim. Anwser'da / anwser'da düzenlendi.
набиячлэвэли

10

POD (düz eski veriler) nesnesi, yapıcı olmadan bu veri türlerinden birine (temel tür, işaretçi, birleşim, yapı, dizi veya sınıf) sahiptir. Tersine, POD olmayan bir nesne, bir yapıcı bulunan nesnedir. Bir POD nesnesi, türüne uygun boyutta bir depolama alanı elde ettiğinde ömrüne başlar ve nesne için depolama alanı yeniden kullanıldığında veya yeniden yerleştirildiğinde ömrü sona erer.

PlainOldData türleri ayrıca şunlardan birine sahip olmamalıdır:

  • Sanal işlevler (kendilerine ait veya kalıtsal)
  • Sanal temel sınıflar (doğrudan veya dolaylı).

PlainOldData öğesinin daha gevşek bir tanımı yapıcıları olan nesneleri içerir; sanal şeyleri olanları hariç tutar. PlainOldData türleriyle ilgili önemli sorun, polimorfik olmamalarıdır. Kalıtım POD tipleri ile yapılabilir, ancak polimorfizm / alt tipleme için değil, sadece ImplementationInheritance (kodun yeniden kullanımı) için yapılmalıdır.

Yaygın (kesin olarak doğru olmasa da) bir tanım, PlainOldData türünün VeeTable'a sahip olmayan bir şey olduğudur.


Cevap çok iyi, ama bu soru 8 yıl önce yanıtı, diğer birkaç iyi yanıtı da kabul etti. Henüz cevaplanmamış soruları cevaplamak için bilgi kullanırsanız
SO'ya

10

Neden POD'lar ile POD olmayanlar arasında ayrım yapmamız gerekiyor?

C ++ hayatına C'nin bir uzantısı olarak başladı. Modern C ++ artık C'nin katı bir üst kümesi değilken, insanlar hala ikisi arasında yüksek düzeyde uyumluluk beklemektedir.

Kabaca söylemek gerekirse, bir POD tipi C ile uyumlu ve belki de aynı derecede önemli olan bazı ABI optimizasyonları ile uyumlu bir türdür.

C ile uyumlu olabilmek için iki kısıtlamayı yerine getirmemiz gerekiyor.

  1. Düzen, karşılık gelen C tipiyle aynı olmalıdır.
  2. Tür, ilgili C türüyle aynı şekilde işlevlere iletilmeli ve işlevlerden döndürülmelidir.

Bazı C ++ özellikleri bununla uyumsuzdur.

Sanal yöntemler, derleyicinin C'de bulunmayan bir şey olan sanal yöntem tablolarına bir veya daha fazla işaretçi eklemesini gerektirir.

Kullanıcı tanımlı kopya oluşturucular, taşıma yapıcılar, kopya atamaları ve yıkıcılar parametre geçirme ve döndürme üzerinde etkilere sahiptir. Birçok C ABI, yazmaçlardaki küçük parametreleri iletir ve döndürür, ancak kullanıcı tanımlı kurucu / tahsis / yıkıcıya iletilen referanslar yalnızca bellek konumlarıyla çalışabilir.

Dolayısıyla, hangi türlerin "C uyumlu" olması beklenebilir ve hangilerinin yapılamayacağını tanımlamaya ihtiyaç vardır. C ++ 03 bu bağlamda biraz fazla katı, herhangi bir kullanıcı tanımlı kurucu yerleşik yapıcıları devre dışı bırakacak ve onları geri eklemek için herhangi bir girişim onları kullanıcı tanımlı ve dolayısıyla türün pod olmayan olur. C ++ 11, kullanıcının yerleşik yapıcıları yeniden tanıtmasına izin vererek işleri biraz açtı.


8

static_assertC ++ 11'den C ++ 17'ye ve POD efektlerine sahip tüm POD dışı vakalara örnekler

std::is_pod C ++ 11'de eklendi, bu yüzden şimdilik bu standardı düşünelim.

std::is_podhttps://stackoverflow.com/a/48435532/895245 adresinde belirtildiği gibi C ++ 20'den kaldırılacak , değiştirmeler için destek geldiğinde bunu güncelleyelim.

Standart geliştikçe POD kısıtlamaları gittikçe daha rahat hale geldi, ben örnekdeki tüm rahatlamaları ifdefs aracılığıyla kapsamayı amaçlıyorum.

libstdc ++, şu adreste küçük testlere sahiptir: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc ama çok az. Bakımcılar: Bu yazıyı okuduysanız lütfen birleştirin. Https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers adresinde belirtilen tüm C ++ testsuite projelerini kontrol etmek için tembelim.

#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 akış yukarı .

Şununla test edildi:

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 kavramı ve tür özelliği std::is_podC ++ 20'de kullanımdan kaldırılacaktır. Daha fazla bilgi için bu soruya bakın .


-7

C ++ ile, Plain Old Data sadece int, char, vb. Gibi şeylerin sadece kullanılan türler olduğu anlamına gelmez. Sade Eski Veriler gerçekten pratikte onu bir bellekten bir yerden diğerine memcpy alabileceğiniz anlamına gelir ve işler tam olarak beklediğiniz gibi çalışır (yani patlamaz). Sınıfınızda veya sınıfınızda bulunan herhangi bir sınıfta, işaretçi veya başvuru olan bir üye veya sanal işlevi olan bir sınıf varsa bu durum kesilir. Esasen, eğer işaretçiler bir yere dahil edilmek zorundaysa, onun Düz Eski Verileri değil.


6
POD yapılarında işaretlere izin verilir. Referanslar değil.
j_random_hacker

1
Burada yolcu eksik.
icbytes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.