Fehlermeldung wenn Instanz ohne new erstellt wird



  • @DocShoe sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    @_ro_ro
    std::stringstream hat keinen Copy-Konstruktor, damit lassen sich auch keine Objekte, die std::string_stream Objekte besitzen kopieren.
    Du könntest den Copy-Konstruktor und Zuweisungsoperator überladen, in denen du dann den Inhalt des stringstreams kopierst (siehe hier).

    Donnerwetter, das ist Fachkompetenz, vielen Dank!!!! Damit muß ich mich mal näher befassen. kriegmer hin 😉

    Viele Grüße!!!



  • @_ro_ro sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    Aber ich will es so

     Foo f = Foo();
    

    Wieso in dieser form?
    Um eine Klasseninstanz ohne new zu erzeugen ist folgendes ausreichend (für dein Beispiel):

    Foo f;
    

    Wenn der Konstruktor der Klasse Parameter erwartet dann sieht das z.b. wie folgt aus:

    class Foo  {
    public:
       Foo(int a) : value(a) {}
    private:
      int value;
    };
    
    Foo f(12);
    

    Wobei deine Form mit C++11 funktioniert (Dank move semantik).
    Seit 4.8.1 von gcc ist C++11 vollständig implementiert im compiler nur nicht default aktiv.
    Um c++11 support zu aktivieren wird folgender Parameter beim aufruf der compilers benötigt:

    -std=c++11
    

    Seit GCC 6 ist der default c++ standard c++14 was ein neuerer standard als c++11 ist.

    Nur ist die Form Foo f = Foo(); nicht notwendig. Und mir ist auch kein Grund bekannt wo diese Form ein nutzen hätte.



  • int f()
    {
       Foo f1; 
       Foo f2 = Foo();
    }
    

    Soweit ich weiß sind beide Formen identisch und der Compiler sollte den Copy-Konstruktor überhaupt nicht benutzen, das wundert mich gerade etwas.

    @_ro_ro :
    Welchen Compiler und welchen C++ Sprachstandard benutzt du?



  • @firefly

    danke auch Dir. Wenn ich eine Instanz mit new erstelle wird der Destruktor nicht aufgerufen und ich muß selber dafür sorgen daß der Speicher wieder freigegeben wird. Und da ich Methoden fremder Klassen über deren Instanzen

            // Delegation Instanz der TE-Klasse
            string render(string templ, map<string,string> stash){
                Templating::TE te = Templating::TE(templ, stash);
                return te.render();
            };
    

    zu eigenen Methoden mache kann das sehr schnell unübersichtlich werden. Das ist der Grund auf new zu verzichten, da brauche ich keinen Pointer.

    Viele Grüße!



  • @_ro_ro

    Die Syntax um in C++ den Konstruktor aufzurufen ist eigentlich:

            // Delegation Instanz der TE-Klasse
            string render(string templ, map<string,string> stash){
                Templating::TE te(templ, stash);
                return te.render();
            };
    

    Dafür brauchst du kein newund kein =.
    Bei

    Templating::TE te = Templating::TE(templ, stash);
    

    Wird theoretisch, auf der rechten Seite ein Objekt erstellt und dann dem Objekt auf der linken Seite zugewiesen und dafür kopiert. Mit "aktuelleren" (ab C++11) Sprachstandards haben wir "Move Semantics". D.h. es wird nicht unbedingt kopiert, sondern, wenn ein Move Assignment existiert (wird häufig vom Compiler zur Verfügung gestellt), wird das Objekt einfach an die richtige Stelle "geschoben" und fertig.

    Edit: Mit neueren C++ Standards (auch ab C++11) kann man auch Templating::TE te{templ, stash}; schreiben.



  • @Schlangenmensch

    danke Dir. Noch mal zum Delegieren:

    Der Aufruf in der eigenen Klasse sieht so aus:

            // in meiner Class Response
            void start_html(){
                string filename = BIN["default"]["tmpldir"]+"/start_html.chtml";            
                start_html_buffer = my::read_file(filename);
                start_html_buffer = render( start_html_buffer, STASH ); // delegiert
            };
    

    Das heißt, daß die TE-Instanz die hinter der delegierten Methode steckt in der eigenen Methode gar nicht sichtbar ist. Ergo kann ich da auch kein delete aufrufen weil ich den Pointer gar nicht habe. Von daher darf die TE-Instanz nicht per new erstellt werden.

    Viele Grüße!



  • @_ro_ro
    Und wo wir uns den Code schon mal etwas genauer ansehen:

    Hast du dich mit den Möglichkeiten der Parameterübergabe mal beschäftigt? Sagen dir Referenzen etwas? Deine render Funktion erzeugt beim Aufruf Kopien der Parameter, was insbesondere bei std::map schnell teuer werden kann. Lies dich bitte mal in die Thematik pass by value vs. pass by reference ein.
    Ich nehme mal an, dass templ und stash nur Kontextinformationen enthalten und nicht beschrieben werden, daher könntest du sie aus Performance-Gründen als const-reference übergeben:

    std::string render( std::string const& templ, std::map<string,string> const& stash){
       Templating::TE te( templ, stash );
       return te.render();
    };
    

    Wenn die Funktion TE::render() als const-deklariert ist kann man auch

    std::string render( std::string const& templ, std::map<string,string> const& stash){
       Templating::TE const te( templ, stash );
       return te.render();
    };
    

    schreiben. Und wofür steht TE eigentlich? Finde ich als Klassennamen wenig aussagekräftig, das stört mich schon.

    Überhaupt solltest du dich mit dem const-Konzept auseinandersetzen und möglichst alles als const deklarieren, was nach der Initialisierung nicht mehr verändert wird. Und auch das Wiederverwenden von lokalen Variablen ist allgemein ein Codesmell:

    void start_html(){
       // der Dateiname wird sich während der Bearbeitung wohl nicht mehr ändern, daher kann man ihn const machen
       std::string const filename = BIN["default"]["tmpldir"]+"/start_html.chtml";            
    
       // was genau passiert hier? Warum ist start_html_buffer erst das eine, und dann was anderes?
       start_html_buffer = my::read_file(filename);
       start_html_buffer = render( start_html_buffer, STASH ); // delegiert
    
       // besser:
       std::string const html_template = my::read_file(filename);
       start_html_buffer = render( html_template , STASH ); // delegiert
    };
    


  • @DocShoe

    Ja natürlich, Übergabe per Referenz, schon korrigiert, danke für den Hinweis. TE steht für TemplatingEngine, dafür habe ich einen dedizierten Namespace "Templating" und von daher ist dann auch der Aufruf selbsterklärend

       Templating::TE;
    

    Viele Grüße!



  • @_ro_ro sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    @DocShoe

    Ja natürlich, Übergabe per Referenz, schon korrigiert, danke für den Hinweis. TE steht für TemplatingEngine, dafür habe ich einen dedizierten Namespace "Templating" und von daher ist dann auch der Aufruf selbsterklärend

       Templating::TE;
    

    Viele Grüße!

    Finde ich nicht, aber gut. Renderer oder RenderingEngine fände ich besser (nachdem, was ich bisher verstanden habe).



  • @DocShoe

    eigentlich so

    Templating::Simple; // Einfache Platzhalter
    Templating::Loop;    // Loops und Platzhalter
    

    aber ich sehe schon, Ihr bringt mich ganz schön auf Trab 😉

    Viele Grüße!



  • @Schlangenmensch sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    Bei
    Templating::TE te = Templating::TE(templ, stash);

    Wird theoretisch, auf der rechten Seite ein Objekt erstellt und dann dem Objekt auf der linken Seite zugewiesen und dafür kopiert. Mit "aktuelleren" (ab C++11) Sprachstandards haben wir "Move Semantics". D.h. es wird nicht unbedingt kopiert, sondern, wenn ein Move Assignment existiert (wird häufig vom Compiler zur Verfügung gestellt), wird das Objekt einfach an die richtige Stelle "geschoben" und fertig.

    Nee. da wird und wurde schon immer der Konstruktor -und nur der Konstruktor- aufgerufen.



  • @Jockelx sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    @Schlangenmensch sagte in Fehlermeldung wenn Instanz ohne new erstellt wird:

    Bei
    Templating::TE te = Templating::TE(templ, stash);

    Wird theoretisch, auf der rechten Seite ein Objekt erstellt und dann dem Objekt auf der linken Seite zugewiesen und dafür kopiert. Mit "aktuelleren" (ab C++11) Sprachstandards haben wir "Move Semantics". D.h. es wird nicht unbedingt kopiert, sondern, wenn ein Move Assignment existiert (wird häufig vom Compiler zur Verfügung gestellt), wird das Objekt einfach an die richtige Stelle "geschoben" und fertig.

    Nee. da wird und wurde schon immer der Konstruktor -und nur der Konstruktor- aufgerufen.

    Dann sollte @_ro_ro den kompletten code zeigen an dem der fehler tatsächlich auftritt.
    Denn aktuell scheint es, dass er nur seine Vermutung welche stelle das problem verursacht haben könnte gepostet hat



  • @firefly

    na, bisher habe ich soweit alles verstanden. Meine Instanzen erhalte ich ganz ohne new und Pointerei jetzt so

      CGI cgi;
      Response response;
    
              // Delegation Instanz Templating::Simple
            string render(const string &templ, const map<string,string> &stash){
                Templating::Simple te = Templating::Simple(templ, stash);
                return te.render();
            };
    

    und übergeben werden Referenzen. const habe ich ergänzt wo es angebracht ist, auch in den darunterliegenden Klassen die ich auch umbenannt habe damit der Name schonmal was sagt.

    Vielen Dank euch allen !



  • @Jockelx Ja, es wird keine Zuweisung ausgeführt, sondern der Copy ctor aufgerufen. Andernfalls wird aber das Objekt direkt initialisiert.
    Siehe copy initialization und direct initialization



  • @Schlangenmensch

    Aha, jetzt verstanden

            // Delegation Instanz der TE-Klasse
            string render(const string &templ, const map<string,string> &stash){
                Templating::Simple te(templ, stash);
                return te.render();
            };
    

    und jetzt Feierabend 😉


Anmelden zum Antworten