Vorweg:
Die Kit-Einstellungen für QT-Creator auf meinem Ubuntu 18 mußte ich nach
langem Hin und Her alle von Hand einstellen.
Das automatisch erzeugte Hallo-Welt funktioniert zwar, jedoch ist es
voller Fehler. Warum funktioniert es trotzdem?
Der Parser verschluckt sich an irgendwas. Das Projekt ist ok, nur die
Interpretation von QtCreator nicht. Es sieht so aus, als ob die
Include-Pfade nicht stimmen und es keine der Header findet.
Hast wohl recht. Alles deutet darauf hin, daß das Prob von meiner
unsauberen Installation kommt.
Viele Fehler sind Forwärtsdeklarationen. Scheint so, als ob was
Wichtiges fehlt.
Ich werd's nochmal neu installieren, das Geraffel.
Der Autor: Sven B. (scummos) Datum: 05.02.2019 11:53 schrieb:
>Liegt vermutlich eher an deiner Kit-Konfiguration.
Da hatte ich die größten Probleme. make, cmake und qmake hab ich in
Verzweiflung mit Trial&Error probiert.
Jetzt sind fast alle Parser-Fehler weg, bis auf einen:
/home/joachim/Versuch/Test_1/mainwindow.h:12: warning: zero as null
pointer constant
Leider ist auf dem Screenshot nicht der Schwebetext des Mauszeigers
drauf, der sagt was von Nullabillity issue und
-Wzero-as-null-pointer-constant
Sieht nach nem Compilerflag aus. Weiß jemand, wo man die Flags setzt?
Autodetect hat für C und C++ angeblich 2x8 Compiler gefunden; und ein
Feld für Compiler-Flags sehe ich auch nicht wirklich.
Dr. Sommer schrieb:> Und du solltest std::unique_ptr für "ui" verwenden :-)
Hmmh, nicht sicher, hast du das ausprobiert? Geht das mit einer Forward
Declaration in diesem Fall?
Der Punkt an diesem merkwürdig wirkenden ui-Pointer-Idiom ist, dass die
Definition der Struktur aus den uic-generierten ui_foo.h-Files kommt.
Die möchte man aber nicht in seinen Headern #includen, weil man sie
nicht installiert, d.h. ein Header (z.B. für ein Widget), der ein
ui_foo.h-File braucht, kann nicht von anderen Projekten verwendet
werden. Die Forward Declaration löst dieses Problem.
Parser schrieb:> Jetzt sind fast alle Parser-Fehler weg, bis auf einen:>>> /home/joachim/Versuch/Test_1/mainwindow.h:12: warning: zero as null> pointer constant
Ja, der QtCreator hat irgendwie in den neusten Versionen extrem
pingelige Warning-Flags eingestellt, die jedes normale Stück Code mit
einem See von Problemem übersäen. Schau mal in den Kit-Einstellungen,
das kann man bestimmt irgendwo umstellen.
Das ist aber kein Fehler, sondern nur eine (vermutlich sogar korrekte)
Warnung, die du auch ignorieren kannst.
Erspart den Destruktor und die Überlegung, ob jetzt "ui" wirklich immer
unter allen Fällen korrekt gelöscht wird... Wäre "ui" ein einfacher
Pointer, und würde man nach "ui" in der "class MainWindow" einen
weiteren Member hinzufügen, dessen Konstruktor eine Exception wirft,
hast du ein Memory-Leak.
Ich bin nicht ganz überzeugt, mit dem gcc 8 hier geht das, aber es wäre
mal interessant welche Compiler das schlucken und welche nicht ;)
Ich sehe hier das potentielle Problem, dass statisch der Destruktor
eines vorwärtsdeklarierten Typs aufgerufen wird ...
Sven B. schrieb:> Ich bin nicht ganz überzeugt, mit dem gcc 8 hier geht das, aber es wäre> mal interessant welche Compiler das schlucken und welche nicht ;)> Ich sehe hier das potentielle Problem, dass statisch der Destruktor> eines vorwärtsdeklarierten Typs aufgerufen wird ...
Wo ist der Unterschied zum Aufruf von delete?
Wie geht man denn am besten vor um herauszufinden wo und wie das
Makefile gemacht wird um den Schalter
-Wzero-as-null-pointer-constant
rauszunehmen?
Oder hat jemand ne bessere Strategie?
mh schrieb:> Sven B. schrieb:>> Ich bin nicht ganz überzeugt, mit dem gcc 8 hier geht das, aber es wäre>> mal interessant welche Compiler das schlucken und welche nicht ;)>> Ich sehe hier das potentielle Problem, dass statisch der Destruktor>> eines vorwärtsdeklarierten Typs aufgerufen wird ...>> Wo ist der Unterschied zum Aufruf von delete?
das steht im cpp-File, wo der Typ komplett bekannt ist
Sven B. schrieb:> mh schrieb:>> Sven B. schrieb:>>> Ich bin nicht ganz überzeugt, mit dem gcc 8 hier geht das, aber es wäre>>> mal interessant welche Compiler das schlucken und welche nicht ;)>>> Ich sehe hier das potentielle Problem, dass statisch der Destruktor>>> eines vorwärtsdeklarierten Typs aufgerufen wird ...>>>> Wo ist der Unterschied zum Aufruf von delete?>> das steht im cpp-File, wo der Typ komplett bekannt ist
Der Destruktor vom unique_ptr wird an der gleichen Stelle aufgerufen,
was soll also anders sein?
Parser schrieb:> Wie geht man denn am besten vor um herauszufinden wo und wie das> Makefile gemacht wird um den Schalter> -Wzero-as-null-pointer-constant> rauszunehmen?> CFLAGS = -pipe -g -Wall -W -D_REENTRANT -fPIE $(DEFINES)
Könnte es vom -Wall kommen?
> Oder hat jemand ne bessere Strategie?
Waroum nicht den code so anpassen das kein Warning getriggert wird?
mh schrieb:> Der Destruktor vom unique_ptr wird an der gleichen Stelle aufgerufen,> was soll also anders sein?
Der Code für den automatisch generierten Destruktor steht im Header, und
da ist der Typ unvollständig. Jetzt weiß ich auch, was man an dem
Beispiel oben ändern muss, damit es nicht mehr geht: man verschiebe mal
das main() in eine extra Datei. Dann bekommt man
1
g++ -o test test.cpp foo.cpp
2
In file included from /usr/include/c++/8.2.1/memory:80,
3
from test.h:1,
4
from foo.h:1,
5
from foo.cpp:1:
6
/usr/include/c++/8.2.1/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Ui::MainWindow]':
Sven B. schrieb:> mh schrieb:>> Der Destruktor vom unique_ptr wird an der gleichen Stelle aufgerufen,>> was soll also anders sein?>> Der Code für den automatisch generierten Destruktor steht im Header, und> da ist der Typ unvollständig.
Mit "Code" meinst du in diesem Fall ein class template.
Sven B. schrieb:> Jetzt weiß ich auch, was man an dem> Beispiel oben ändern muss, damit es nicht mehr geht: man verschiebe mal> das main() in eine extra Datei. Dann bekommt man> g++ -o test test.cpp foo.cpp> In file included from /usr/include/c++/8.2.1/memory:80,> from test.h:1,> from foo.h:1,> from foo.cpp:1:> /usr/include/c++/8.2.1/bits/unique_ptr.h: In instantiation of 'void> std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp => Ui::MainWindow]':> /usr/include/c++/8.2.1/bits/unique_ptr.h:274:17: required from> 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Ui::MainWindow;> _Dp = std::default_delete<Ui::MainWindow>]'> test.h:7:7: required from here> /usr/include/c++/8.2.1/bits/unique_ptr.h:79:16: error: invalid> application of 'sizeof' to incomplete type 'Ui::MainWindow'> static_assert(sizeof(_Tp)>0,> ^~~~~~~~~~~>> wie erwartet.>> Was man aber machen kann, ist einen Destruktor deklarieren und im cpp> definieren (als leer), dann geht es.
Der Typ muss, wie erwartet, vollständig bekannt sein, wenn der
Destruktor vom unique_ptr instaziiert wird. An diesem Punkt muss der Typ
aber auch für delete bekannt sein (nicht immer, aber man ist im
Grenzgebiet von "undefiend behaviour land"), wenn man keinen unique_ptr
nutzt.
mh schrieb:> Der Typ muss, wie erwartet, vollständig bekannt sein, wenn der> Destruktor vom unique_ptr instaziiert wird. An diesem Punkt muss der Typ> aber auch für delete bekannt sein (nicht immer, aber man ist im> Grenzgebiet von "undefiend behaviour land"), wenn man keinen unique_ptr> nutzt.
Ja. Aber: so wie es oben im Beispiel aufgeschrieben ist, funktioniert es
i.A. nicht, weil das nicht der Fall ist. Eben weil das für den
automatisch erzeugten Default-Destruktor nicht gilt.
Parser schrieb:> Jetzt sind fast alle Parser-Fehler weg, bis auf einen:>> /home/joachim/Versuch/Test_1/mainwindow.h:12: warning: zero as null> pointer constant
Unter Help -> Plugins kannst du die Parser-Warnings ein-/ausschalten.
Welche genau für deine Warning ist, weiß ich aber auch nicht.
mfg
Sven B. schrieb:> mh schrieb:>> Der Typ muss, wie erwartet, vollständig bekannt sein, wenn der>> Destruktor vom unique_ptr instaziiert wird. An diesem Punkt muss der Typ>> aber auch für delete bekannt sein (nicht immer, aber man ist im>> Grenzgebiet von "undefiend behaviour land"), wenn man keinen unique_ptr>> nutzt.>> Ja. Aber: so wie es oben im Beispiel aufgeschrieben ist, funktioniert es> i.A. nicht, weil das nicht der Fall ist. Eben weil das für den> automatisch erzeugten Default-Destruktor nicht gilt.
Was ist nicht der Fall? Was gilt nicht für den Default-Destruktor?
Ich gehe davon aus, dass der Typ vollständig bekannt ist, da sonst ein
delete gefährlich ist. Wenn der Typ vollständig bekannt ist kann man
auch unique_ptr inkl. Destruktor instanzieren.
mh schrieb:>> Ja. Aber: so wie es oben im Beispiel aufgeschrieben ist, funktioniert es>> i.A. nicht, weil das nicht der Fall ist. Eben weil das für den>> automatisch erzeugten Default-Destruktor nicht gilt.>> Was ist nicht der Fall? Was gilt nicht für den Default-Destruktor?
Probier's doch einfach aus, tu das main() in eine eigene cpp-Datei, in
der du nur den Header und nicht das auto-genierte inkludierst und
bewundere den Compilerfehler.
Der Default-Destruktor wird in der .h-Datei generiert, den explizit
hingeschriebenen kann man hingegen in die .cpp-Datei schreiben. In
ersterer ist der Typ unvollständig, und deshalb kompiliert es mit dem
Default-Destruktor nicht.
Das Beispiel funktioniert nur, weil die einzige Verwendung des
Default-Destruktors in der Compilation Unit ist, wo auch der
auto-generierte Code inkludiert wird. Teile es in zwei Compilation Units
auf, und es geht nicht mehr.