Forum: Compiler & IDEs Projekt wird trotz Parser-Fehlern compiliert. Warum?


von Parser (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Sven B. (scummos)


Lesenswert?

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.

von Parser (Gast)


Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

Liegt vermutlich eher an deiner Kit-Konfiguration. Warum hast du da 
alles selber gemacht, ging das Preset nicht ...?

von Dr. Sommer (Gast)


Lesenswert?

Und du solltest std::unique_ptr für "ui" verwenden :-)

von Walter (Gast)


Lesenswert?

steht in deiner mainwindow.h
#include <QWidget>
?

von Parser (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

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 ...

von mh (Gast)


Lesenswert?

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?

von Parser (Gast)


Lesenswert?

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?

von Sven B. (scummos)


Lesenswert?

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

von mh (Gast)


Lesenswert?

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?

von Blubb (Gast)


Lesenswert?

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?

von Sven B. (scummos)


Lesenswert?

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
von mh (Gast)


Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

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.

von Felix F. (wiesel8)


Lesenswert?

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

von mh (Gast)


Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

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
Noch kein Account? Hier anmelden.