Fehlermeldung wenn Instanz ohne new erstellt wird
-
@_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?
-
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!
-
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
new
und kein=
.
BeiTemplating::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.
-
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, dasstempl
undstash
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 auchstd::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 };
-
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:
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
oderRenderingEngine
fände ich besser (nachdem, was ich bisher verstanden habe).
-
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
-
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
-
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