std::array C++11



  • Da ich die Größe meines Speichers zur Compilezeit kenne und diese sich auch zur Laufzeit niemals ändern wird wäre doch ein std::array sinnvoller als ein std::vector?

    Allerdings scheint ein std::array auf dem Stack zu liegen und damit ist die Größe beschränkt. Also macht es doch wieder keinen Sinn folgendes zu bauen und damit schon ~1MB vom Stack zu klauen?

    #include <array>
    
    std::array<FooClass, 1 << 16> ht;  // sizeof(FooClass) = 64 Byte
    

    Also trotz Array-Eigenschaften doch lieber einen Vector verwenden, oder?

    #include <vector>
    
    std::vector<FooClass> ht(1 << 16);  // sizeof(FooClass) = 64 Byte
    

    😕



  • du kannst auch einen std::unique_ptr als vector ohne overhead missbrauchen.



  • Was sagt da eigentlich der Standard zu std::array? In §23.3.2 steht nix darüber, dass der Speicher auf dem Stack liegen muss (oder übersehe ich da was?)

    Wäre es dann nicht angebracht, dass array selbst entscheidet, wann ein Array auf dem Stack oder dem Heap liegen soll?!



  • Nun, ein std::array ist ein "aggregate type with the same semantics as a struct holding a C-style array". Nicht der Array entscheidet, wo er zu liegen kommt, sondern der Programmierer.

    array<int, 3> a; // Stack
    auto *b = new array<int, 3>; // Heap.
    

    Zu Tomahawk: Ja, std::array macht hier mehr Sinn. Du musst es ja nicht unbedingt auf den Stack hauen, sondern kannst es irgendwo platzieren.

    FG


  • Mod

    auto *b = new array<int, 3>; // Heap.
    

    Und was ist das? Eigentlich nur ein vector . Aber mit Zeigern. Unschön.

    Nein, hier brauchst du einfach einen vector , dem du bei der Initialisierung die Größe mitgibst. Damit hast du auch nur eine Heap-Allokation, also praktisch genauso schnell wie bei array .

    Edit:

    Wäre es dann nicht angebracht, dass array selbst entscheidet, wann ein Array auf dem Stack oder dem Heap liegen soll?!

    Du denkst an std::dynarray .

    (oder übersehe ich da was?)

    Schau mal in die Header-Vorgabe. Da steht genau, wie std::array zu definieren ist. Das einzige Member-Objekt ist ein Array:

    T elems[N]; // exposition only [von §23.3.2.1/3]
    


  • Es ging mir um das Prinzip. Der Programmierer bestimmt, wo der Speicher liegt, da std::array im Prinzip nur ein simples struct ohne Pointer ist. Du kannst den std::vector gerne auf den Stack werfen; seine Elemente liegen aber nicht dort, sondern in der Regel eben auf dem Heap.

    Deklarierst du hingegen den std::array auf dem Stack, dann liegen auch die Elemente dort. Deklarierst du den Array global, dann liegen die Elemente im Data Segment (oder wo auch immer). Ein Array besteht aus seinen Elementen und sonst gar nichts. Ein Vector besteht aus irgend etwas, in der Regel aus zwei Zeigern, damit die Elemente irgendwo liegen können.



  • Arcoth schrieb:

    Schau mal in die Header-Vorgabe. Da steht genau, wie std::array zu definieren ist. Das einzige Member-Objekt ist ein Array:

    T elems[N]; // exposition only [von §23.3.2.1/3]
    

    Genau das ist der Knackpunkt. Die wörtliche Übersetzung für exposition ist sowas wie Ausstellung. Ich würde das sinngemäß so übersetzen wie "Nur ums zu zeigen wie es gehen könnte". Sprich: das Array könnte auch sonst wie implementiert sein.

    Moment, mir fällt auch grad ein, der Standard kennt ja sowas wie Heap oder Stack gar nicht...


  • Mod

    Nein, nein. Der Kommentar heißt hier einfach, dass der Name des Arrays nur als Beispiel gegeben ist, und kein tatsächlicher Member von array ist.


  • Mod

    17.5.2.3 lesen und verstehen


  • Mod

    camper schrieb:

    17.5.2.3 lesen und verstehen

    Es kann praktisch nur ein echtes Array als Member geben. Der Standard fordert eine Initialisierungssyntax (s. §23.3.2.1/2), die nur ein Array als Member ermöglicht. Ein vector fällt durch, weil brace-elision nur für Aggregate funktioniert.

    Die einzige andere Möglichkeit besteht darin, das Subaggregat so zu definieren, dass es genauso viele Member hat wie das Template-Argument vorgibt. Das ist nur leider impraktikabel, da so nur eine maximale Größe von 4096 möglich wäre - siehe Anhang B.


  • Mod

    also mir fällt da so ein

    template <typename T, size_t N>
    struct array
    {
    ...
        T elems[1][1][1][1][1][N][1][1][1][1];
    };
    

    oder

    template <typename T, std::size_t N>
    struct array
    {
        array<T,(N+1)/2> x;
        array<T,N/2> y;
    };
    template <typename T>
    struct array<T,1>
    {
        T x;
    };
    template <typename T>
    struct array<T,0>
    {
    };
    

  • Mod

    😡 Eines Tages erwisch' ich dich, du mieser Hund!


  • Mod

    Warte! Letzteres ist gar nicht Standardkonform, weil...

    Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other

    Und

    The elements of an array are stored contiguously, meaning that if a is an array<T, N> then it obeys the identity &a[n] == &a[0] + n for all 0 <= n < N .



  • Skym0sh0 schrieb:

    Wäre es dann nicht angebracht, dass array selbst entscheidet, wann ein Array auf dem Stack oder dem Heap liegen soll?!

    Das wäre fein, sagen wir mal ab 65k geht's auf den Heap.

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?


  • Mod

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?

    Warum nicht einfach selber was basteln? Mit partieller Spezialisierung ist das ein Klacks. Muss doch nicht in den Standard, dynarray hats auch nicht geschafft.

    Und ich will mal sehen, wie man da um den Standard herum kommt, gerade wegen der Speicherkontinuitätsregel und der Initialisierungssyntax. Ich wette, jetzt gehen auch camper die Ideen aus.


  • Mod

    Hier, so ähnlich:

    #include <vector>
    #include <memory>
    
    template< typename T, std::size_t N, typename=void >
    struct Array
    {
    	T _elems[N]; // evt. mit Trick um zero-size-arrays zu erlauben
    
    	// ...
    };
    
    template< typename T, std::size_t N >
    struct Array<T, N, typename std::enable_if<N >= (1 << 16)>::type>
    {
    	std::unique_ptr<T[]> _elems{ new T[N] };
    
    	// ..
    };
    
    int main()
    {
    	Array<int, 70000> a;
    }
    

    So ist es sogar immer noch ein Aggregat.



  • Arcoth schrieb:

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?

    Warum nicht einfach selber was basteln? Mit partieller Spezialisierung ist das ein Klacks. Muss doch nicht in den Standard, dynarray hats auch nicht geschafft.

    Jo, was lokales dazu habe ich schon seit 10 Jahren, naja so ähnlich, den Vector<type,size,onHeap=(size>=8192)> oder so. Array brauche ich eher nie, weil irgendwie die Daten dann doch angekrochen oder gestreamt oder berechnet mit ungewisser Ergebnisanzahl oder so kommen.

    Wenn ich man drüber nachdenke, würde wohl auch >=64 fast reichen, denn wenn man die 64 Elemente tatsächlich anfassen will, kostet gegen die Berechnungen im Vector/Array das Allokieren/Deallokieren gar nicht mehr als einen Takt pro Element. Pah, 64-Bitter packen 8192 kompromisslos. Hast mich wieder zu nutzlosem Nachdenken gebracht, Du Schalk.


  • Mod

    Ich - bin - kein - Schalk! Du bist der Schalk!



  • Arcoth schrieb:

    Ich - bin - kein - Schalk! Du bist der Schalk!

    Wird noch, ich setze weiterhin große Hoffnungen in Dich.


  • Mod

    Arcoth schrieb:

    Warte! Letzteres ist gar nicht Standardkonform, weil...

    Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other

    genau: might
    Nirgendwo wird verlangt, dass die Implementation der Standardbibliothek portabel sein muss.

    Arcoth schrieb:

    template< typename T, std::size_t N >
    struct Array<T, N, typename std::enable_if<N >= (1 << 16)>::type>
    {
    	std::unique_ptr<T[]> _elems{ new T[N] };
    
    	// ..
    };
    

    So ist es sogar immer noch ein Aggregat.

    Ich glaube nicht. Initialisierer für nicht-statischen Member und so...


Log in to reply