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.
Liegt vermutlich eher an deiner Kit-Konfiguration. Warum hast du da alles selber gemacht, ging das Preset nicht ...?
Und du solltest std::unique_ptr für "ui" verwenden :-)
steht in deiner mainwindow.h #include <QWidget> ?
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.
Sven B. schrieb: > Geht das mit einer Forward > Declaration in diesem Fall? So in der Art? Ja.
1 | // -- Header
|
2 | #include <memory> |
3 | |
4 | namespace Ui { |
5 | class MainWindow; |
6 | }
|
7 | |
8 | class MainWindow { |
9 | public:
|
10 | MainWindow (); |
11 | private:
|
12 | std::unique_ptr<Ui::MainWindow> ui; |
13 | };
|
14 | |
15 | // -- Autogenerierter Header
|
16 | #include <iostream> |
17 | namespace Ui { |
18 | class MainWindow { |
19 | public:
|
20 | MainWindow () { std::cout << "Ui::MainWindow::MainWindow ()\n"; } |
21 | ~MainWindow () { std::cout << "Ui::MainWindow::~MainWindow ()\n"; } |
22 | };
|
23 | }
|
24 | |
25 | // -- Source
|
26 | |
27 | MainWindow::MainWindow () : ui (new Ui::MainWindow ()) { |
28 | }
|
29 | |
30 | int main () { |
31 | MainWindow mw; |
32 | }
|
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?
zu der lästigen Warnung: -Wzero-as-null-pointer-constant findsch im Makefile nix dazu.
1 | MAKEFILE = Makefile |
2 | |
3 | ####### Compiler, tools and options
|
4 | |
5 | CC = gcc |
6 | CXX = g++ |
7 | DEFINES = -DQT_DEPRECATED_WARNINGS -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB |
8 | CFLAGS = -pipe -g -Wall -W -D_REENTRANT -fPIE $(DEFINES) |
9 | CXXFLAGS = -pipe -g -std=c++0x -Wall -W -D_REENTRANT -fPIE $(DEFINES) |
10 | INCPATH = -I../../Qt/5.1.0/gcc_64/mkspecs/linux-g++ -I../Test_3 -I../../Qt/5.1.0/gcc_64/include -I../../Qt/5.1.0/gcc_64/include/QtWidge$ |
11 | LINK = g++ |
12 | LFLAGS = -Wl,-rpath,/home/joachim/Qt/5.1.0/gcc_64 -Wl,-rpath,/home/joachim/Qt/5.1.0/gcc_64/lib |
13 | LIBS = $(SUBLIBS) -L/home/joachim/Qt//5.1.0/gcc_64/lib -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread |
14 | AR = ar cqs |
15 | RANLIB = |
16 | QMAKE = /home/joachim/Qt/5.1.0/gcc_64/bin/qmake |
17 | TAR = tar -cf |
18 | COMPRESS = gzip -9f |
19 | COPY = cp -f |
20 | SED = sed |
21 | COPY_FILE = cp -f |
22 | COPY_DIR = cp -f -R |
23 | STRIP = strip |
24 | INSTALL_FILE = install -m 644 -p |
25 | INSTALL_DIR = $(COPY_DIR) |
26 | ...
|
27 | ... und so weiter |
28 | ...
|
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]': |
7 | /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>]' |
8 | test.h:7:7: required from here |
9 | /usr/include/c++/8.2.1/bits/unique_ptr.h:79:16: error: invalid application of 'sizeof' to incomplete type 'Ui::MainWindow' |
10 | static_assert(sizeof(_Tp)>0, |
11 | ^~~~~~~~~~~ |
wie erwartet. Was man aber machen kann, ist einen Destruktor deklarieren und im cpp definieren (als leer), dann geht es.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.