Was sind POD-Typen in C ++?


977

Ich bin ein paar Mal auf diesen Begriff POD-Typ gestoßen.
Was bedeutet das?



5
Weitere Informationen zur akzeptierten Antwort finden Sie unter chat.stackoverflow.com/transcript/message/213026#213026 und in den Nachrichten des folgenden Tages
Johannes Schaub - litb


@ paxos1977: Bitte ändern Sie Ihre Auswahl an "Lösung" (derzeit Hewgills Antwort), damit eine grundlegend falsche Antwort Googler, die hier landen, nicht irreführt.
Prost und hth. - Alf

Wir sind zu dem Schluss gekommen, dass eine Zeichenfolge im C-Stil KEIN POD-Typ ist, da 1.) der Zeiger nicht an die Zeichenfolgendaten angrenzt und 2.) um eine Zeichenfolge zu einem POD-Typ zu machen, müssten Sie den Typ sicherstellen Es enthielt ein Null-Term-Zeichen innerhalb der vordefinierten Größe des POD-Typs, was zu undefiniertem Verhalten führte.

Antworten:


694

POD steht für Plain Old Data - eine Klasse (ob mit dem Schlüsselwort structoder dem Schlüsselwort definiert class) ohne Konstruktoren, Destruktoren und Funktionen für virtuelle Mitglieder. Der Wikipedia-Artikel über POD geht etwas detaillierter vor und definiert ihn als:

Eine einfache alte Datenstruktur in C ++ ist eine Aggregatklasse, die nur PODS als Mitglieder enthält, keinen benutzerdefinierten Destruktor, keinen benutzerdefinierten Kopierzuweisungsoperator und keine nicht statischen Elemente vom Typ Zeiger auf Mitglied hat.

Weitere Details finden Sie in dieser Antwort für C ++ 98/03 . C ++ 11 hat die Regeln für POD geändert und stark gelockert, sodass hier eine Antwort erforderlich ist .


34
Es besteht ein Unterschied. Intrinsische Typen sind die "eingebauten" Sprachprimitive. POD-Typen sind diese plus Aggregationen dieser (und anderer PODs).
Adam Wright

59
POD-Typen haben Eigenschaften, die Nicht-POD-Typen nicht haben. Wenn Sie beispielsweise eine globale Struktur vom Typ POD vom Typ const haben, können Sie deren Inhalt mit Klammernotation initialisieren, sie wird in den Nur-Lese-Speicher gestellt und es muss kein Code generiert werden, um sie zu initialisieren (Konstruktor oder auf andere Weise). weil es Teil des Programmbildes ist. Dies ist wichtig für eingebettete Benutzer, bei denen RAM, ROM oder Flash häufig stark eingeschränkt sind.
Mike DeSimone

34
In C ++ 11 können Sie mit std :: is_pod <MyType> () feststellen, ob MyType POD ist.
Allyourcode

7
Der technische Bericht von Bjarne Stroustrup zur C ++ - Leistung besagt, dass der C ++ - Standard einen POD als " einen Datentyp beschreibt, der in Layout, Initialisierung und seiner Fähigkeit, mit memcpy kopiert zu werden, mit dem entsprechenden Datentyp in C kompatibel ist ". Vielleicht sollte zwischen einem POD-Typ und einer POD-Struktur unterschieden werden.
user34660

6
−1 Diese Antwort ist zum 16. August 2016 immer noch grundlegend falsch und irreführend: POD-Typen sind nicht auf Klassentypen beschränkt.
Prost und hth. - Alf

352

Sehr informell:

Ein POD ist ein Typ (einschließlich Klassen), bei dem der C ++ - Compiler garantiert, dass in der Struktur keine "Magie" stattfindet: zum Beispiel versteckte Zeiger auf vtables, Offsets, die auf die Adresse angewendet werden, wenn sie in andere Typen umgewandelt wird ( Zumindest wenn auch der POD des Ziels), Konstruktoren oder Destruktoren. Grob gesagt ist ein Typ ein POD, wenn die einzigen darin enthaltenen Dinge eingebaute Typen und Kombinationen davon sind. Das Ergebnis ist etwas, das sich wie ein C-Typ "verhält".

Weniger informell:

  • int, char, wchar_t, bool, float, doubleSind PODs, wie sind long/shortund signed/unsignedVersionen davon.
  • Zeiger (einschließlich Zeiger auf Funktion und Zeiger auf Mitglied) sind PODs,
  • enums sind PODs
  • a constoder volatilePOD ist ein POD.
  • a class, structoder unionvon Hohlkörpern ist ein POD vorausgesetzt , dass alle nicht-statische Datenelemente sind public, und es hat keine Basisklasse und keine Konstruktoren, Destruktoren oder virtuelle Methoden. Statische Mitglieder hören nach dieser Regel nicht auf, dass etwas ein POD ist. Diese Regel hat sich in C ++ 11 geändert und bestimmte private Mitglieder sind zulässig: Kann eine Klasse mit allen privaten Mitgliedern eine POD-Klasse sein?
  • Wikipedia ist falsch zu sagen, dass ein POD keine Mitglieder vom Typ Zeiger auf Mitglied haben kann. Oder besser gesagt, es ist korrekt für den C ++ 98-Wortlaut, aber TC1 hat deutlich gemacht, dass Zeiger auf Mitglieder POD sind.

Formal (C ++ 03 Standard):

3.9 (10): "Arithmetische Typen (3.9.1), Aufzählungstypen, Zeigertypen und Zeiger auf Elementtypen (3.9.2) und cv-qualifizierte Versionen dieser Typen (3.9.3) sind kollektiv aufrufende Skalartypen. Skalar Typen, POD-Strukturtypen, POD-Vereinigungstypen (Abschnitt 9), Arrays solcher Typen und cv-qualifizierte Versionen dieser Typen (3.9.3) werden zusammen als POD-Typen bezeichnet. "

9 (4): "Eine POD-Struktur ist eine Aggregatklasse, die keine nicht statischen Datenelemente vom Typ Nicht-POD-Struktur, Nicht-POD-Vereinigung (oder Array solcher Typen) oder Referenz hat und keine Benutzer- hat. Definieren Sie einen Kopieroperator und keinen benutzerdefinierten Destruktor. In ähnlicher Weise ist eine POD-Vereinigung eine aggregierte Vereinigung, die keine nicht statischen Datenelemente vom Typ Nicht-POD-Struktur, Nicht-POD-Vereinigung (oder Array solcher Typen) oder Referenz enthält. und hat keinen benutzerdefinierten Kopieroperator und keinen benutzerdefinierten Destruktor.

8.5.1 (1): "Ein Aggregat ist ein Array oder eine Klasse (Klausel 9) ohne vom Benutzer deklarierte Konstruktoren (12.1), ohne private oder geschützte nicht statische Datenelemente (Klausel 11), ohne Basisklassen (Klausel 10). und keine virtuellen Funktionen (10.3). "


3
Sie haben formelle / weniger formelle. Sie können eine Faustregel hinzufügen. Eingebaute Typen und Aggregationen von Eingebauten Typen (oder so ähnlich). Um die genaue Definition zu erhalten, müssen wir das Wissen benutzerfreundlich machen.
Martin York

1
Sie sind ein bisschen falsch in Bezug auf das Bit "Offsets bei Besetzung eines anderen Typs". Diese Offsets werden beim Casting auf eine Basis- oder abgeleitete Klasse angewendet. Wenn Sie also von einem POD-Basisklassenzeiger auf eine nicht von POD abgeleitete Klasse umwandeln, kann es dennoch zu einer Anpassung kommen.
MSalters

1
@Steve Jessop: Warum müssen wir überhaupt zwischen PODs und Nicht-PODs unterscheiden?
Lazer

6
@Lazer: Das ist eine ganz andere Frage: "Wie verhalten sich PODs?" im Gegensatz zu "Was bedeutet POD?". Zusammenfassend bezieht sich der Unterschied auf die Initialisierung (daher auch die Verwendung von memcpy zum Duplizieren von Objekten), die Kompatibilität mit dem C-Struktur-Layout für diesen Compiler und das Hoch- und Herunterwerfen von Zeigern. PODs "verhalten sich wie C-Typen", Nicht-PODs können dies nicht garantieren. Wenn Sie also möchten, dass sich Ihr Typ portabel wie eine C-Struktur verhält, müssen Sie sicherstellen, dass es sich um POD handelt. Daher müssen Sie den Unterschied kennen.
Steve Jessop

4
@muntoo: Es war wirklich so, dass ich die Antwort kommentierte, die veraltete Informationen aus Wikipedia zitiert. Ich könnte diese Antwort bearbeiten, nehme ich an, aber ich rieche Ärger, wenn ich die Antwort anderer Leute bearbeite, um meiner zuzustimmen, egal wie richtig ich denke, dass ich bin.
Steve Jessop

20

Einfache alte Daten

Kurz gesagt, ist es alle eingebauten Datentypen (zB int, char, float, long, unsigned char, double, etc.) und alle Aggregation von POD - Daten. Ja, es ist eine rekursive Definition. ;)

Um es klarer zu machen, ein POD ist das, was wir "eine Struktur" nennen: eine Einheit oder eine Gruppe von Einheiten, die nur Daten speichern.


12
Es ist wahr, dass wir sie manchmal "eine Struktur" nennen. Wir sind jedoch immer falsch, da eine Struktur nicht unbedingt ein POD-Typ ist.
Steve Jessop

6
Natürlich ... Struktur und Klasse sind fast gleichwertig, aber in "the business" nennen wir "eine Struktur" einen einfachen Datensammler, normalerweise ohne ctors und dtor, normalerweise mit
Wertsemantik

2
Für mich war es C ++ falsch, struct mit dem Schlüsselwort class identisch zu machen oder in der Nähe von: struct fügt nur öffentlichen Standardzugriff auf class hinzu. Es war einfacher, C-ähnliche Strukturen zu erstellen, und wir hätten am Tag 0 von c ++ PODs gehabt.
user1708042

ugasoft: Ihre Antwort kann irreführend sein - Ihr Kommentar erklärte das fehlende Detail, dass es in der Praxis eher als Standard verwendet wird. Whoa, 8 Jahre, bist du überhaupt hier? ;-)
Hauron

Mit Ausnahme einer Zeichenfolge, da Sie diese nicht mit memcpy kopieren können, ohne zuvor die Zeichenfolgenlänge zu bestimmen.

12

Soweit ich weiß, handelt es sich bei POD (PlainOldData) nur um Rohdaten, die nicht benötigt werden:

  • gebaut werden,
  • zerstört sein,
  • benutzerdefinierte Operatoren zu haben.
  • Darf keine virtuellen Funktionen haben,
  • und darf Operatoren nicht überschreiben.

Wie überprüfe ich, ob etwas ein POD ist? Nun, dafür gibt es eine Struktur namens 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)>
  { };
}

(Aus dem Header type_traits)


Referenz:


2
Falsch, ein POD-Typ kann Elementfunktionen oder überladene Operatoren haben. (Aber es kann nicht virtuelle Mitgliedsfunktionen haben.)
Colin D Bennett

@ColinDBennett Ja, das stimmt. Entschuldigung für die Verwirrung. In / aus der Antwort bearbeitet.
набиячлэвэли

10

Ein POD-Objekt (Plain Old Data) hat einen dieser Datentypen - einen Grundtyp, einen Zeiger, eine Vereinigung, eine Struktur, ein Array oder eine Klasse - ohne Konstruktor. Umgekehrt ist ein Nicht-POD-Objekt eines, für das ein Konstruktor existiert. Ein POD-Objekt beginnt seine Lebensdauer, wenn es Speicher mit der richtigen Größe für seinen Typ erhält, und seine Lebensdauer endet, wenn der Speicher für das Objekt entweder wiederverwendet oder freigegeben wird.

PlainOldData-Typen dürfen außerdem keine der folgenden Eigenschaften haben:

  • Virtuelle Funktionen (entweder eigene oder geerbte)
  • Virtuelle Basisklassen (direkt oder indirekt).

Eine lockerere Definition von PlainOldData enthält Objekte mit Konstruktoren. schließt aber diejenigen mit virtuellem irgendetwas aus. Das wichtige Problem bei PlainOldData-Typen ist, dass sie nicht polymorph sind. Die Vererbung kann mit POD-Typen erfolgen, sollte jedoch nur für ImplementationInheritance (Wiederverwendung von Code) und nicht für Polymorphismus / Subtypisierung erfolgen.

Eine übliche (wenn auch nicht streng korrekte) Definition ist, dass ein PlainOldData-Typ alles ist, was keine VeeTable hat.


Ihre Antwort ist sehr gut, aber diese Frage hat die Antwort vor 8 Jahren akzeptiert, plus einige andere gute Antworten. Sie können mehr zu SO beitragen, wenn Sie Ihr Wissen verwenden, um Fragen zu beantworten, die noch nicht beantwortet wurden)))
mvidelgauz

10

Warum müssen wir überhaupt zwischen PODs und Nicht-PODs unterscheiden?

C ++ begann sein Leben als Erweiterung von C. Während modernes C ++ keine strikte Obermenge von C mehr ist, erwarten die Leute immer noch ein hohes Maß an Kompatibilität zwischen beiden.

Grob gesagt ist ein POD-Typ ein Typ, der mit C kompatibel ist und vielleicht ebenso wichtig mit bestimmten ABI-Optimierungen kompatibel ist.

Um mit C kompatibel zu sein, müssen wir zwei Bedingungen erfüllen.

  1. Das Layout muss mit dem entsprechenden C-Typ übereinstimmen.
  2. Der Typ muss auf dieselbe Weise wie der entsprechende C-Typ an Funktionen übergeben und von diesen zurückgegeben werden.

Bestimmte C ++ - Funktionen sind damit nicht kompatibel.

Bei virtuellen Methoden muss der Compiler einen oder mehrere Zeiger auf virtuelle Methodentabellen einfügen, was in C nicht vorhanden ist.

Benutzerdefinierte Kopierkonstruktoren, Verschiebungskonstruktoren, Kopierzuweisungen und Destruktoren haben Auswirkungen auf die Übergabe und Rückgabe von Parametern. Viele C-ABIs übergeben und geben kleine Parameter in Registern zurück, aber die an den benutzerdefinierten Konstruktor / Zuweisung / Destruktor übergebenen Referenzen können nur mit Speicherorten arbeiten.

Es muss also definiert werden, welche Typen voraussichtlich "C-kompatibel" sind und welche nicht. C ++ 03 war in dieser Hinsicht etwas zu streng. Jeder benutzerdefinierte Konstruktor würde die integrierten Konstruktoren deaktivieren, und jeder Versuch, sie wieder hinzuzufügen, würde dazu führen, dass sie benutzerdefiniert sind und der Typ daher kein Pod ist. C ++ 11 hat die Dinge ziemlich geöffnet, indem es dem Benutzer ermöglicht hat, die integrierten Konstruktoren erneut einzuführen.


8

Beispiele für alle Nicht-POD-Fälle mit static_assertC ++ 11 bis C ++ 17 und POD-Effekten

std::is_pod wurde in C ++ 11 hinzugefügt, also betrachten wir diesen Standard erst einmal.

std::is_podwird aus C ++ 20 entfernt, wie unter https://stackoverflow.com/a/48435532/895245 erwähnt. Aktualisieren wir dies, sobald die Unterstützung für die Ersetzungen eintrifft.

POD-Einschränkungen wurden mit der Entwicklung des Standards immer lockerer. Ich möchte alle Relaxationen im Beispiel durch ifdefs abdecken.

libstdc ++ hat einige Tests unter: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc aber es einfach zu wenig. Betreuer: Bitte führen Sie dies zusammen, wenn Sie diesen Beitrag lesen. Ich bin faul, alle C ++ - Testsuite-Projekte zu überprüfen, die unter /software/199708/is-there-a-compliance-test-for-c-compilers erwähnt werden

#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 stromaufwärts .

Getestet mit:

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

unter Ubuntu 18.04, GCC 8.2.0.


4

Das Konzept von POD und das Typmerkmal std::is_podwerden in C ++ 20 nicht mehr unterstützt. Weitere Informationen finden Sie in dieser Frage.


-7

In C ++ bedeutet "Einfache alte Daten" nicht nur, dass nur Dinge wie "int", "char" usw. verwendet werden. Einfache alte Daten bedeuten in der Praxis wirklich, dass Sie eine Struktur von einem Speicherort zum anderen speichern können und die Dinge genau so funktionieren, wie Sie es erwarten würden (dh nicht explodieren). Dies bricht ab, wenn Ihre Klasse oder eine Klasse, die Ihre Klasse enthält, als Mitglied einen Zeiger oder eine Referenz oder eine Klasse mit einer virtuellen Funktion hat. Wenn Zeiger irgendwo beteiligt sein müssen, handelt es sich im Wesentlichen nicht um einfache alte Daten.


6
Zeiger sind in POD-Strukturen zulässig. Referenzen sind nicht.
j_random_hacker

1
Passant fehlt hier.
icbytes
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.