guidelines - iso c++
Quali sono i tipi di POD in C++? (6)
Ho incontrato questo termine POD-type alcune volte. Cosa significa?
Molto informalmente:
Un POD è un tipo (incluse le classi) in cui il compilatore C ++ garantisce che non ci sarà "magia" nella struttura: ad esempio puntatori nascosti a vtables, offset che vengono applicati all'indirizzo quando viene lanciato su altri tipi ( almeno se il POD del target), costruttori o distruttori. In parole povere, un tipo è un POD quando le uniche cose in esso contenute sono tipi e combinazioni incorporati. Il risultato è qualcosa che "si comporta come" un tipo C.
Meno informalmente:
-
int
,char
,wchar_t
,bool
,float
,double
sono i POD, così come le versionilong/short
esigned/unsigned
. - i puntatori (inclusi pointer-to-function e pointer-to-member) sono POD,
-
enums
sono i POD - un POD
const
ovolatile
è un POD. - una
class
,struct
ounion
di POD è un POD a condizione che tutti i membri di dati non statici sianopublic
e che non abbia classe di base e nessun costruttore, distruttore o metodo virtuale. I membri statici non smettono di essere un POD sotto questa regola. Questa regola è cambiata in C ++ 11 e alcuni membri privati sono autorizzati: una classe con tutti i membri privati può essere una classe POD? - Wikipedia ha torto nel dire che un POD non può avere membri di tipo pointer-to-member. O meglio, è corretto per la dicitura C ++ 98, ma TC1 ha reso esplicito che i puntatori a membro sono POD.
Formalmente (standard C ++ 03):
3.9 (10): "I tipi aritmetici (3.9.1), i tipi di enumerazione, i tipi di puntatore e il puntatore ai tipi di membro (3.9.2) e le versioni qualificate cv di questi tipi (3.9.3) sono tipi scalari del chiamante collettivamente. i tipi, i tipi POD-struct, i tipi POD-union (clausola 9), gli array di tali tipi e le versioni qualificate cv di questi tipi (3.9.3) sono collettivamente chiamati tipi POD "
9 (4): "Un POD-struct è una classe aggregata che non ha membri di dati non statici di tipo non POD-struct, non POD-union (o array di tali tipi) o riferimento, e non ha user- definire un operatore di copia e nessun distruttore definito dall'utente. Allo stesso modo un POD-union è un'unione aggregata che non ha membri di dati non statici di tipo non POD-struct, non POD-union (o array di tali tipi) o riferimento, e non ha un operatore di copia definito dall'utente né un distruttore definito dall'utente.
8.5.1 (1): "Un aggregato è un array o una classe (clausola 9) senza costruttori dichiarati dall'utente (12.1), nessun membro di dati non statici privato o protetto (clausola 11), nessuna classe di base (clausola 10) e nessuna funzione virtuale (10.3). "
Come ho capito POD (PlainOldData) è solo un dato grezzo - non ha bisogno di:
- essere costruito,
- essere distrutto,
- avere operatori personalizzati.
- Non deve avere funzioni virtuali,
- e non deve ignorare gli operatori.
Come verificare se qualcosa è un POD? Bene, c'è una struttura per quello chiamato 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)>
{ };
}
(Dall'intestazione type_traits)
Riferimento:
Il concetto di POD e il tipo tratto std::is_pod
saranno deprecati in C ++ 20. Vedi this domanda per ulteriori informazioni.
Un oggetto POD (plain old data) ha uno di questi tipi di dati - un tipo fondamentale, puntatore, unione, struct, array o classe - senza alcun costruttore. Viceversa, un oggetto non POD è uno per il quale esiste un costruttore. Un oggetto POD inizia il suo ciclo di vita quando ottiene lo spazio di archiviazione con le dimensioni appropriate per il suo tipo e il suo ciclo di vita termina quando lo spazio di archiviazione per l'oggetto viene riutilizzato o deallocato.
I tipi PlainOldData inoltre non devono avere nessuno dei:
- Funzioni virtuali (proprie o ereditate)
- Classi di base virtuali (dirette o indirette).
Una definizione più flessibile di PlainOldData include oggetti con costruttori; ma esclude quelli con qualcosa virtuale. Il problema importante con i tipi PlainOldData è che non sono polimorfici. L'ereditarietà può essere effettuata con i tipi POD, tuttavia dovrebbe essere eseguita solo per ImplementationInheritance (riutilizzo del codice) e non per polimorfismo / sottotipizzazione.
Una definizione comune (sebbene non strettamente corretta) è che un tipo PlainOldData è tutto ciò che non ha una VeeTable.
POD è l' acronimo di Plain Old Data , ovvero una classe (definita con la parola chiave struct
o la parola chiave class
) senza funzioni di costruttori, distruttori e membri virtuali. L'articolo di Wikipedia su POD va un po 'più in dettaglio e lo definisce come:
Una semplice struttura dei dati obsoleti in C ++ è una classe aggregata che contiene solo PODS come membri, non ha un distruttore definito dall'utente, nessun operatore di assegnazione copia definito dall'utente e nessun membro non statico del tipo puntatore-membro.
Maggiori dettagli possono essere trovati in questa risposta per C ++ 98/03 . C ++ 11 ha cambiato le regole che circondano il POD, rilassandole notevolmente, richiedendo quindi una risposta di follow-up qui .
Esempi di tutti i possibili casi non POD con static_assert
da C ++ 11 a C ++ 17
std::is_pod
stato aggiunto in C ++ 11, quindi consideriamo lo standard in poi per ora.
std::is_pod
sarà rimosso da C ++ 20 come menzionato su https://.com/a/48435532/895245 , aggiorniamolo come supporto per le sostituzioni.
Le restrizioni POD sono diventate sempre più rilassate con lo standard evoluto, mirando a coprire tutti i rilassamenti con l'esempio.
libstdc ++ ha un piccolo bit di testing su: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc ma troppo poco Manutentori: si prega di unire questo se leggete questo post. Sono pigro per controllare tutti i progetti menzionati su: https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers Se qualcuno ha realizzato un progetto del genere, lui o lei sarebbe diventata famosa.
Per favore aiutami a uccidere tutti i TODO mancanti con le tue modifiche, guru C ++.
#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
}
Testato con:
for std in 11 14 17; do echo $std; g++-8 -std=c++$std pod.cpp; done
su Ubuntu 18.04.
Elenco di tutti gli effetti POD noti all'uomo
C'è già una lista su: https://.com/a/4178176/895245 ma voglio TUTTI con esempi o link ad esempi per lo meno, per favore modifica via:
-
__attribute__((packed))
viene ignorato su non-POD: ignorando l'attributo packed a causa del campo non POD non imballato che a sua volta impedisce lamemcpy
sicura di tali classi.