wieso crashed die Anwendung bei der Allokation eines std::array



  • Ich habe eine Klasse die type-erasure implementiert (aus Sean Parents Vortrag)

    class Anything
    {
    public:
      Anything() = default;
      template <typename T>
      Anything(T x) : self_(std::make_shared<model_t<T>>(std::move(x))){}
    
    private: 
      struct concept_t
      {
        virtual ~concept_t() = default;
      };
    
      template <typename T>
      struct model_t : concept_t
      {
        //    explicit model_t(T&& x)
        //      : data_(std::forward<T>(x))
        explicit model_t(T x) : data_(std::move(x)){}
    
        T data_;
      }; 
    
    public:
      std::shared_ptr<const concept_t> self_;
    };
    

    Weiterhin habe ich ein Datenobjekt, dass ein Array enthält

    class Data{
     std::array<float, 250000> data_;
    };
    

    Ich verwende diese Klasse wie folgt

    std::vector<Anything> vec;
    vec.emplace_back(Data{});
    

    und bekomme beim ausführen

    The program has unexpectedly finished.

    geschmissen.

    Verwende ich allerdings perfect-forwarding (oben auskommentiert) läuft das Programm. Kann mir jemand sagen wo das Problem liegt?

    die nested-class concept_t hat ja einen virtual destructor womit die move operationen impliziert deleted sind. Aber wieso funktioniert dann die Variante mit forward?

    Danke schon mal



  • Du erzeugst 250.000 floats aufm Stack, ist der groß genug? Das sind immerhin 1MB. Wenn das nur 1x kopiert wird brauchste schon 2MB aufm Stack, und IIRC ist die default Stackgröße 1MB.



  • ok, ich dachte ich sei Schlau und lege den Speicher aufem Stack an, da ich die benötigte Größe vorher weíß und stack memory doch schneller ist.

    und wieso funktioniert es dann mit forward anstatt move?


  • Global Moderator

    Sewing schrieb:

    und stack memory doch schneller ist.

    Denkst du, dass der computer da spezielle, super-schnelle Stack-Speicherriegel hat?



  • und stack memory doch schneller ist.

    Stack != Cache - dein Stack ist auch im RAM

    nur das "allokieren" auf dem Stack ist schneller, der Stack aber auch viel viel kleiner und man kann nur schwer (Platform/Kompiler-Neutral/Optimierungsfest) rausfinden wieviel Platz noch frei ist



  • Ok danke Jungs 🙂

    drei Fragen noch bitte:

    [1]was ist denn dann der Anwendungsbereich von std::array wenn der Zugriff gleich schnell wie der bei std::vector erfolgt. Einfach etwas schlanker in der Struktur?
    [2]Wieso funktioniert das Ganze denn mit std::forward im obigen Beispiel aber nicht mit std::move?
    [3]in der Klasse concept_t sind die move operationen implizit deleted wegen des virtual destructors. Werden die Move operationen benötigt, wenn ich ein Object Anything mit einer Instanz von Anything initialisiere, also den copy-ctor von Anything aufrufe? Habe gerade etwas Probleme mir das vorzustellen. Eigentlich werden doch die member einzeln kopiert, dh. der ref-count des pointers erhöht sich, aber die Model Klasse verwendet nur den definierten custom ctor oder?

    Zu 2 ist die Erklärung wohl, dass beim forwarding die universal reference eine Kopie umgeht, gerade mal nachgelesen:
    This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. Unlike a C-style array, it doesn't decay to T automatically.*

    also kopier ich da durch das pass-by-value das gesamte Array. Sind universal references dann nicht dem pass-by-value idiom mit anschließendem move vorzuziehen? bei rvalues refs wird forward doch sowieso zu move