Warum kann keine Forward-Deklaration für einen std::vector verwendet werden?

StackOverflow https://stackoverflow.com/questions/37346

  •  09-06-2019
  •  | 
  •  

Frage

Wenn ich eine Klasse wie folgt erstelle:

// B.h
#ifndef _B_H_
#define _B_H_

class B
{
private:
    int x;
    int y;
};

#endif // _B_H_

und benutze es so:

// main.cpp
#include <iostream>
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A() {
        std::cout << v.size() << std::endl;
    }

private:
    std::vector<B> v;
};

int main()
{
    A a;
}

Der Compiler schlägt beim Kompilieren fehl main.cpp.Jetzt ist die Lösung, die ich kenne, folgende #include "B.h", aber ich bin neugierig, warum es fehlschlägt.Weder g++ oder clDie Fehlermeldungen von 's waren in dieser Angelegenheit sehr aufschlussreich.

War es hilfreich?

Lösung

Der Compiler muss wissen, wie groß „B“ ist, bevor er die entsprechenden Layoutinformationen generieren kann.Wenn stattdessen, sagten Sie std::vector<B*>, dann müsste der Compiler nicht wissen, wie groß B ist, weil er weiß, wie groß ein Zeiger ist.

Andere Tipps

Tatsächlich würde Ihr Beispiel erstellt, wenn der Konstruktor von A in einer Kompilierungseinheit implementiert würde, die den Typ von B kennt.

Eine std::vector-Instanz hat eine feste Größe, unabhängig von T, da sie, wie andere bereits sagten, nur einen Zeiger auf T enthält.Der Konstruktor des Vektors hängt jedoch vom konkreten Typ ab.Ihr Beispiel lässt sich nicht kompilieren, weil A() versucht, den Ctor des Vektors aufzurufen, der ohne Kenntnis von B nicht generiert werden kann.Folgendes würde funktionieren:

Erklärung von A:

// A.h
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A(); // only declare, don't implement here

private:
    std::vector<B> v;
};

A's Implementierung:

// A.cpp
#include "A.h"
#include "B.h"

A::A() // this implicitly calls vector<B>'s constructor
{
    std::cout << v.size() << std::endl;
}

Jetzt muss ein Benutzer von A nur A kennen, nicht B:

// main.cpp
#include "A.h"

int main()
{
    A a; // compiles OK
}

Um A::v zu ​​instanziieren, muss der Compiler den konkreten Typ von B kennen.

Wenn Sie versuchen, die Menge an #included baggage zu minimieren, um die Kompilierungszeiten zu verkürzen, können Sie zwei Dinge tun, die eigentlich Variationen voneinander sind:

  1. Verwenden Sie einen Zeiger auf B
  2. Verwenden Sie ein Leichtgewicht Proxy zu B

Es ist mehr als nur die Größe B erforderlich.Moderne Compiler verfügen über ausgefallene Tricks, um Vektorkopien beispielsweise mithilfe von memcpy zu beschleunigen, wo dies möglich ist.Dies wird üblicherweise durch eine teilweise Spezialisierung auf die POD-Qualität des Elementtyps erreicht.Sie können anhand einer Forward-Deklaration nicht erkennen, ob B ein POD ist.

Wie fyzix bereits sagte, liegt der Grund dafür, dass Ihre Forward-Deklaration nicht funktioniert, in Ihrem Inline-Konstruktor.Sogar ein leerer Konstruktor kann viel Code enthalten, wie zum Beispiel die Konstruktion von Nicht-POD-Mitgliedern.In Ihrem Fall müssen Sie einen Vektor initialisieren, was nicht möglich ist, ohne seinen Vorlagentyp vollständig zu definieren.

Das Gleiche gilt für Destruktoren.Der Vektor benötigt die Definition des Vorlagentyps, um anzugeben, welcher Destruktor aufgerufen werden soll, wenn die darin enthaltenen Instanzen zerstört werden.

Um dieses Problem zu beseitigen, sollten Sie einfach keine Inline-Konstruktoren und Destruktoren verwenden.Definieren Sie sie separat irgendwo, nachdem B vollständig definiert ist.

Für mehr Informationen,http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

Dabei spielt es keine Rolle, ob Sie einen Vektor verwenden oder einfach nur versuchen, ein B zu instanziieren.Die Instanziierung erfordert die vollständige Definition eines Objekts.

Mann, du instanziierst std::vector mit unvollständigem Typ.Berühren Sie nicht die Forward-Deklaration, sondern verschieben Sie einfach die Definition des Konstruktors in die .cpp Datei.

Der Grund, warum Sie keine Forward-Deklaration verwenden können, liegt darin, dass die Größe von B unbekannt ist.

In Ihrem Beispiel gibt es keinen Grund, warum Sie B.h nicht in A.h einbeziehen können. Welches Problem versuchen Sie also wirklich zu lösen?

Bearbeiten: Es gibt auch eine andere Möglichkeit, dieses Problem zu lösen:Hören Sie auf, C/C++ zu verwenden!Es ist so 1970er Jahre...;)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top