Pergunta

Eu me deparei com este termo POD-digitar algumas vezes. O que isso significa?

Foi útil?

Solução

POD significa Plain dados antigos - ou seja, uma classe (se definido com a palavra chave struct ou a palavra-chave class) sem construtores, destruidores e funções membros virtuais. O artigo de Wikipedia sobre POD entra em um pouco mais detalhadamente e define-o como:

Estrutura A Plain dados antigos em C ++ é uma classe de agregados que contém apenas VAGENS como membros, não tem destruidor definido pelo utilizador, nenhum operador atribuição de cópia definido pelo utilizador, e não há membros nonstatic de tipo de ponteiro-para-membro.

Maiores detalhes podem ser encontrados em esta resposta para C ++ 98/03 . C ++ 11 mudou as regras que cercam POD, relaxando-os muito, assim que necessitam de uma resposta de acompanhamento aqui .

Outras dicas

Muito informalmente:

A POD é um tipo (incluindo classes), onde o C ++ garante compilador que não haverá "mágica" acontecendo na estrutura: por exemplo escondido ponteiros para vtables, compensações que são aplicadas para o endereço quando ele é convertido para outros tipos (pelo menos se POD do alvo também), construtores ou destruidores. Grosso modo, um tipo é um POD quando as únicas coisas em que estão embutidos tipos e combinações dos mesmos. O resultado é algo que "funciona como" um tipo C.

Menos informalmente:

  • int, char, wchar_t, bool, float, double são PODs, como são long/short e signed/unsigned versões deles.
  • ponteiros (incluindo ponteiro-para-função e ponteiro-para-membro) são vagens,
  • enums são PODs
  • a const ou volatile POD é um POD.
  • a class, struct ou union de PODs é um POD, desde que todos os membros de dados não-estáticos são public, e não tem nenhuma classe base e nenhum construtor, destruidores ou métodos virtuais. Membros estáticos não parar de algo ser um POD sob esta regra. Esta regra mudou em C ++ 11 e certos membros particulares são permitidos: pode uma classe com todos os membros privados ser uma classe POD?
  • A Wikipédia é errado dizer que um POD não pode ter membros de tipo de membro de ponteiro-to-. Ou melhor, é correto para o C ++ 98 redação, mas TC1 explicitado que pointers-para-membro são POD.

Formalmente (C ++ 03 Padrão):

3.9 (10): "fortes tipos aritméticos (3.9.1), tipos de enumeração, tipos de ponteiro, e ponteiro de tipos de membros (3.9.2) e versões CV-qualificado destes tipos (3,9 0,3) são colectivamente tipos chamador escalares. escalares tipos, tipos POD-struct, tipos POD-união (cláusula 9), arrays de tais tipos e versões de cv-qualificado destes tipos (3.9.3) são colectivamente chamados tipos POD "

9 (4): "Uma POD-estrutura é uma classe de agregados que não tem membros de dados não-estáticos de não-POD-estrutura tipo, não-POD-união (ou matriz de tal tipos) ou de referência, e não tem qualquer operador cópia e não destruidor definido pelo utilizador. de forma semelhante um POD-união é uma união de agregados que não tem membros de dados não-estáticos de não-POD-estrutura tipo definir pelo utilizador, não-POD-união (ou uma matriz desses tipos) ou de referência, e não tem nenhuma cópia operador definir pelo utilizador e sem destruição definida pelo utilizador.

8.5.1 (1): "Um agregado é um conjunto ou classe (cláusula 9) com nenhum construtor declarado pelo utilizador (12,1), não há membros de dados privadas ou protegidas não-estático (cláusula 11), há classes base (cláusula 10) e há funções virtuais (10,3). "

Plain dados antigos

Em suma, é tudo embutido tipos de dados (por exemplo int, char, float, long, unsigned char, double, etc.) e todos os dados de agregação de POD. Sim, é uma definição recursiva. ;)

Para ser mais claro, a POD é o que chamamos de "uma estrutura":. Uma unidade ou um grupo de unidades que os dados apenas store

Como eu entendo POD (PlainOldData) é apenas a dados brutos - que não precisa:

  • a ser construído,
  • para ser destruído,
  • para ter operadores personalizados.
  • Não deve ter funções virtuais,
  • e não deve substituir operadores.

Como verificar se algo é um POD? Bem, há uma estrutura para que chamou 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)>
  { };
}

(De type_traits cabeçalho)


Referência:

A POD (plain dados antigos) objeto tem um desses tipos de dados - um tipo fundamental, ponteiro, união, struct, array, ou classe - com nenhum construtor. Por outro lado, um objecto não-POD é uma para a qual existe um construtor. Um objecto POD começa a sua vida útil quando se obtém o armazenamento com o tamanho apropriado para o seu tipo e as suas extremidades ao longo da vida quando o armazenamento para o objecto é reutilizados ou desatribuído.

tipos PlainOldData também não deve ter qualquer um:

  • funções virtuais (ou a sua própria, ou herdado)
  • classes base virtuais (diretos ou indiretos).

Uma definição mais flexível de PlainOldData inclui objetos com construtores; mas exclui aqueles com qualquer coisa virtual. A questão importante com tipos PlainOldData é que eles são não-polimórfico. A herança pode ser feito com tipos de PI, no entanto, só deve ser feito para ImplementationInheritance (reutilização de código) e não polimorfismo / subtipagem.

Um comum (embora não estritamente correta) definição é que um tipo PlainOldData é qualquer coisa que não tem um VeeTable.

Exemplos de todos os casos não-POD com static_assert de C ++ 11 C ++ para 17 e efeitos POD

std::is_pod foi adicionado em C ++ 11, então vamos considerar esse padrão em diante por agora.

std::is_pod será removido a partir de C ++ 20 como mencionado em https://stackoverflow.com/a/48435532/895245, vamos atualizar este como o apoio chega para as substituições.

restrições POD tornaram-se mais e mais relaxado como o padrão evoluiu, eu não pretendem abranger todos os relaxamentos no exemplo através IFDEFs.

libstdc ++ tem pelo pouquinho de testes em: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/ value.cc mas apenas muito pouco. Mantenedores: Por favor, mescle isso se você ler este post. Eu sou preguiçoso para verificar todo o C ++ projectos testsuite mencionados em: https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers

#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
}

GitHub montante .

Testado com:

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

no Ubuntu 18.04, GCC 8.2.0.

O conceito de POD e o traço std::is_pod tipo será suspenso em C ++ 20. Consulte esta questão para mais informações.

Por que precisamos de diferenciar entre POD e não-POD em tudo?

C ++ começou sua vida como uma extensão do C. Enquanto C ++ moderno não é mais um super rigoroso de C, as pessoas ainda esperam um alto nível de compatibilidade entre os dois.

A grosso modo, um tipo POD é um tipo que é compatível com C e talvez igualmente importante é compatível com certas otimizações ABI.

Para ser compatível com C, é preciso satisfazer duas restrições.

  1. A disposição deve ser o mesmo que o tipo C correspondente.
  2. O tipo deve ser transmitido para e retornados de funções da mesma maneira como o tipo C correspondente.

Certain C ++ características são incompatíveis com este.

métodos virtuais requerem o compilador para inserir um ou mais ponteiros para tabelas de métodos virtuais, algo que não existe em C.

definidos pelo usuário construtores de cópia, construtores mover, copiar atribuições e destruidores têm implicações para a passagem de parâmetros e retornando. Muitos passagem C ABIs e retornar pequenos parâmetros em registos, mas as referências passadas para o usuário definido construtor / assigment / destructor só pode trabalhar com posições de memória.

Portanto, há uma necessidade de definir quais os tipos pode ser esperado para ser "C compatível" e que tipos não pode. C ++ 03 foi um pouco sobre-estrita a este respeito. C ++ 11 abriu as coisas um pouco.

Com C ++, Plain Old Dados não significa apenas que coisas como int, char, etc são os únicos tipos usados. Plain Old dados realmente significa na prática que você pode tomar um memcpy struct lo de um local na memória para outro e as coisas vão funcionar exatamente como você esperaria (ou seja, não explodir). Isso quebra se sua classe, ou qualquer classe a classe contém, tem como um membro que é um ponteiro ou uma referência ou uma classe que tem uma função virtual. Essencialmente, se ponteiros têm que estar em algum lugar envolvido, a sua não Plain dados antigos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top