Perché non è possibile utilizzare una dichiarazione anticipata per un std::vettore?

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

  •  09-06-2019
  •  | 
  •  

Domanda

Se creo una classe in questo modo:

// B.h
#ifndef _B_H_
#define _B_H_

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

#endif // _B_H_

e usarlo in questo modo:

// 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;
}

Il compilatore fallisce durante la compilazione main.cpp.Ora la soluzione che conosco è quella #include "B.h", ma sono curioso di sapere perché fallisce.Nessuno dei due g++ O clI messaggi di errore di sono stati molto illuminanti in merito.

È stato utile?

Soluzione

Il compilatore deve sapere quanto è grande la "B" prima di poter generare le informazioni di layout appropriate.Se invece, hai detto std::vector<B*>, allora il compilatore non avrebbe bisogno di sapere quanto è grande B perché sa quanto è grande un puntatore.

Altri suggerimenti

In effetti, il tuo esempio verrebbe creato se il costruttore di A fosse implementato in un'unità di compilazione che conosce il tipo di B.

Un'istanza std::vettoriale ha una dimensione fissa, non importa cosa sia T, poiché contiene, come altri hanno detto prima, solo un puntatore a T.Ma il costruttore del vettore dipende dal tipo concreto.Il tuo esempio non viene compilato perché A() tenta di chiamare il ctor del vettore, che non può essere generato senza conoscere B.Ecco cosa funzionerebbe:

Dichiarazione di 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:

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

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

Ora un utente di A deve conoscere solo A, non B:

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

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

Per istanziare A::v, il compilatore deve conoscere il tipo concreto di B.

Se stai cercando di ridurre al minimo la quantità di bagaglio #incluso per migliorare i tempi di compilazione, ci sono due cose che puoi fare, che in realtà sono una variazione l'una dell'altra:

  1. Utilizzare un puntatore a B
  2. Usa un peso leggero procura essere

Ciò che serve non è solo la dimensione B.I compilatori moderni avranno trucchi fantasiosi per accelerare le copie vettoriali utilizzando memcpy ove possibile, ad esempio.Ciò si ottiene comunemente specializzandosi parzialmente sul POD del tipo di elemento.Non puoi dire se B è un POD da una dichiarazione anticipata.

Proprio come ha detto fyzix, il motivo per cui la tua dichiarazione anticipata non funziona è a causa del tuo costruttore inline.Anche un costruttore vuoto potrebbe contenere molto codice, come la costruzione di membri non POD.Nel tuo caso, hai un vettore da inizializzare, cosa che non puoi fare senza definire completamente il suo tipo di modello.

Lo stesso vale per i distruttori.Il vettore necessita della definizione del tipo di modello per indicare quale distruttore chiamare quando si distruggono le istanze che contiene.

Per eliminare questo problema, basta non incorporare costruttori e distruttori.Definiteli separatamente da qualche parte dopo che B sarà completamente definito.

Per maggiori informazioni,http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

Questo non importa se usi un vettore o provi semplicemente a istanziarne uno B.L'istanziazione richiede la definizione completa di un oggetto.

Amico, stai istanziando std::vector con un tipo incompleto.Non toccare la dichiarazione forward, sposta semplicemente la definizione del costruttore nel file .cpp file.

Il motivo per cui non è possibile utilizzare una dichiarazione anticipata è perché la dimensione di B è sconosciuta.

Non c'è motivo nel tuo esempio per cui non puoi includere B.h all'interno di A.h, quindi quale problema stai veramente cercando di risolvere?

Modificare: C'è anche un altro modo per risolvere questo problema:smetti di usare C/C++!Sono così anni '70...;)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top