O structură de date simplă ( de exemplu , date vechi simple , POD ) este un tip de date în limbaje moderne de programare de nivel înalt, care are o aranjare rigidă a câmpurilor în memorie care nu necesită restricții de acces și control automat . Variabilele de acest tip pot fi copiate cu rutine simple de copiere în memorie precum . Opusul este o structură de date gestionată . memcpy
Cel mai simplu mod de a defini o structură de date simplă este prin contradicție. Dacă compilatorul rearanjează în secret câmpurile de la utilizator sau când creează o structură de date, apelează în secret constructorul sau apelează destructorul atunci când structura este distrusă sau la copiere - o procedură specială de copiere, atunci aceasta este o procedură gestionată (adică , nu simplă) structură.
Structurile simple de date au două caracteristici.
Compilatorul poate reconstrui automat structura datelor la discreția sa (de exemplu, schimba ordinea câmpurilor. În limbajul C++, acest lucru este posibil numai dacă există o etichetă de acces public/privat/protejat între câmpuri. O secvență de câmpuri care nu sunt separate printr-o astfel de etichetă trebuie să fie plasate în memorie în ordinea declarației de câmp). O astfel de restructurare poate economisi serios memorie, dar rupe compatibilitatea. În POD-uri, această optimizare este dezactivată.
Cu alte cuvinte: tipurile marcate POD sunt aranjate în memorie exact așa cum a descris programatorul (poate cu o anumită aliniere ). Prin urmare, numai POD-urile pot fi folosite pentru a comunica între două biblioteci de rulare . În special, pentru a transfera date de la program la program, de la plugin la plugin, pentru a comunica cu cod scris într-un alt limbaj de programare . Pentru a scrie rapid un antet de fișier complex, cum ar fi BMP , pe disc , îl puteți forma în memorie și apoi îl puteți scrie cu o singură comandă - dar structura de date în care formăm antetul trebuie să fie și un POD.
Aceasta înseamnă că atunci când apare un obiect, nu trebuie să apelați constructorul, atunci când copiați, operația de atribuire și când distrugeți, destructorul. Aceasta, la rândul său, oferă următoarele beneficii:
În C++ , POD este definit prin contradicție. Un tip de date este un POD dacă:
Conform standardului C++, un tip de date simplu este structurat exact așa cum este descris (și este pe deplin compatibil octet cu octet în aspectul memoriei cu o structură C). Compilatorul poate reorganiza structura gestionată în modul pe care îl consideră cel mai eficient.
Definiție POD pre-C++11:
Un agregat este fie o matrice, fie o clasă care nu are:
Un agregat poate fi inițializat (ca în C) cu o listă de forma = {1, 2, 3};
Scalarul se numește:
(adică un tip care nu este o clasă, o matrice sau o referință)
Un POD este fie un scalar , fie o matrice de alte POD-uri, fie o clasă care este un agregat și, în plus:
„Dispozitiv previzibil în memorie” și „fără cod de control” sunt proprietăți de tip similare, dar diferite. De exemplu, structura de date STRRET[ 2] , care în Windows este folosită pentru a trece șiruri de caractere de la un manager de memorie la altul, poate fi „ înfășurată ” în cod de control, dar a doua proprietate, dispozitivul previzibil, rămâne. Prin urmare, conceptul de POD-uri în C++11 este împărțit în trei.
O clasă se numește „avand un constructor de copie trivial” dacă toate următoarele sunt adevărate:
Constructorul de copiere trivial generat automat este memmove().
Termenii „având un constructor implicit banal/operator de atribuire/constructor de mutare/operator de mutare” sunt definiți exact în același mod.
O clasă se numește „având un destructor trivial” dacă toate următoarele sunt adevărate:
O astfel de clasă nu necesită distrugere, iar memoria care o conține poate fi dealocată fără a fi curățată.
Se spune că o clasă este „trivial copiabilă” dacă toate funcțiile membre speciale de mai sus sunt banale (cu excepția constructorului implicit, care poate fi non-trivial). Scalarii, precum și matricele de obiecte care pot fi copiate trivial, sunt, de asemenea, copiabile. Astfel de tipuri pot fi copiate prin memcpy.
O clasă se numește „trivial” dacă este trivial copiabilă și are, de asemenea, un constructor implicit trivial.
Cu alte cuvinte, o clasă este trivială dacă are:
O clasă este un tip de dispozitiv standard dacă:
Să clarificăm ultima condiție: în limbaj nu pot exista două obiecte diferite de același tip cu aceeași adresă, ceea ce înseamnă că dimensiunea unei clase goale (fără câmpuri nestatice) nu poate fi 0 (cel puțin 1). Cu toate acestea, se face o excepție pentru „partea B din clasa D : B” iar dimensiunea acesteia (dacă este goală) poate fi strict zero, rezultând că nu există „completare” între începutul lui D și primul său câmp. Dar, în același timp, dacă tipul primului câmp este și B, excepția nu poate fi aplicată, deoarece (B *) & d și & (d. câmp 1) indică obiecte diferite de același tip și, prin urmare, " căptușeală” este necesară. Ultima condiție din lista de mai sus nu înseamnă altceva decât „în clasele unui dispozitiv standard, o astfel de garnitură este interzisă”.
Astfel de tipuri au un dispozitiv previzibil în memorie (de exemplu, adresa unui obiect în ansamblu este aceeași cu adresa primului său câmp, desigur, după reinterpret_cast la același tip, de exemplu, pentru a anula *), pot să fie trecut la o altă bibliotecă de rulare și la programare în alte limbaje.
Apoi POD este o matrice de alte POD-uri, sau un scalar, sau o clasă trivială cu un dispozitiv standard, toate câmpurile non-statice ale cărora sunt și POD-uri.
Pentru a lucra cu constante de timp de compilare și inițializare statică, C++11 are un concept mai ușor - un tip literal . Și anume:
De la C++03, există o diferență între T t; și T t();, precum și între noul T și noul T().
Versiunea cu paranteze goale se numește „inițializarea valorii”, iar fără ele se numește „inițializarea implicită”.
Inițializare implicită: dacă constructorul implicit este banal, atunci nu se face nimic, gunoiul rămâne în obiect. Dacă constructorul implicit nu este banal, atunci este executat.
Inițializare după valoare: dacă există un constructor implicit scris explicit, atunci acesta este executat. Dacă nu (adică dacă constructorul implicit este banal sau este generat automat), atunci obiectul este anulat mai întâi și numai atunci constructorul este executat (dacă nu este trivial). Tipurile scalare sunt setate la zero atunci când sunt inițializate cu o valoare.
Toate tipurile sunt considerate structuri de date simple, cu excepția: