2011-12-11 10 views
11

Diciamo che hoVettore di strutture con membri const?

#include <string> 
#include <vector> 
using namespace std; 

struct Student 
{ 
    const string name; 
    int grade; 
    Student(const string &name) : name(name) { } 
}; 

Come faccio, quindi, mantenere un vettore di studenti?

int main() 
{ 
    vector<Student> v; 

    // error C2582: 'operator =' function is unavailable in 'Student' 
    v.push_back(Student("john")); 
} 

C'è anche un modo per fare questo, o devo allocare tutti gli studenti sul mucchio, e memorizzare un puntatore a ciascuno di loro, invece?

+0

Questo sembra compilare e collegare con VC 2010. Puoi fornire ulteriori informazioni sul tuo ambiente? È un caso di test completo che riproduce questo errore di compilazione? – DRH

+0

@DRH: I'm on VC 2008, mi dispiace. E sì, questo è l'intero test case. – Mehrdad

+0

Mentre per altre operazioni è necessario l'operatore di assegnazione, non riesco a pensare a nessun possibile motivo per cui 'push_back' avrebbe quel requisito ... quindi, di nuovo, potrebbe essere che l'implementazione controlli il requisito' Assegnabile'. –

risposta

7

Non è possibile. Il tuo tipo viola il requisito "Assegnabile" per i contenitori standard.

ISO/IEC 14882: 2003 23.1 [lib.container.requirements]/3:

Il tipo di oggetti memorizzati in questi componenti devono soddisfare i requisiti di CopyConstructible tipi (20.1.3), e i requisiti aggiuntivi dei tipi Assignable.

Dalla tabella 64 (Assignable requisiti):

In Tabella 64, T è del tipo utilizzato per istanziare il contenitore, t è un valore di T, e u è un valore (possibilmente const) T.

espressione: t = u; tipo di reso: T; post-condizione: t è equivalente a u

In teoria, un std::vector equivalente potrebbe scegliere di fare la distruzione e copiare la costruzione in tutti i casi, ma non è il contratto che è stato scelto. Se non è richiesta la riallocazione, utilizzare l'operatore di assegnazione del tipo contenuto per elementi come vector::operator= e vector::assign potrebbe essere significativamente più efficiente.

+0

Oh huh ... quindi deve essere assegnabile anche se non assegno mai nulla? Non lo sapevo. – Mehrdad

+0

@Philipp: In realtà, il vettore non assegna nulla durante la riallocazione. Solitamente copia o sposta solo il nuovo intervallo e quindi elimina quello vecchio. –

+0

Hmm ... Perché 'vector' esegue i compiti di copia? Non può copiare costruzione + distruzione, invece di usare 'operator ='? – Mehrdad

8

La semplice risposta è: non è possibile. Se si dispone delle variabili membro const, il compilatore non può fornire un operatore di assegnazione copia predefinito. Tuttavia, molte delle operazioni fornite da std::vector devono eseguire assegnazioni e pertanto richiedono un operatore (pubblico) di assegnazione delle copie.

Le opzioni disponibili sono:

  1. Fai name non const.
  2. Scrivere il proprio operatore di assegnazione delle copie e pensare a un modo per gestire "copia" di un membro const.
1

Gli elementi dei vettori devono essere copiabili, che la struttura dello Student non è a causa del membro const. È sufficiente utilizzare string name anziché const string name. A meno che non si abbia un requisito specifico, i membri costanti nelle classi sono raramente utili. Se si desidera impedire modifiche al membro, renderlo privato e aggiungere una funzione getter pubblica.

3

A vector A spesso è necessario spostare gli elementi.Ogni volta che un vettore deve crescere quando si chiama push_back(), rialloca la memoria per mantenersi contigua e copia tutti gli elementi esistenti nel nuovo spazio. Inoltre, se si chiama insert() o remove() gli elementi devono essere spostati . Per vector essere in grado di fare tutto ciò che gli elementi devono essere assegnabili alla copia, il che significa che il tipo che si memorizza nel vettore deve avere l'operatore di assegnazione definito.

In genere, se si definisce una classe, il compilatore genererà l'operatore di assegnazione per tale classe. Tuttavia, ci sono casi in cui il compilatore non è in grado di farlo. Uno di questi casi è quando la classe ha membri costanti (nota che i puntatori a const sono ok).

Quindi, nel tuo caso, il problema è il const string name. Impedisce al compilatore di generare operator=(), che a sua volta impedisce la compilazione di vector, anche se in realtà non si utilizza l'assegnazione sui suoi elementi.

Una soluzione è rendere name non-const. L'altro è quello di scrivere il proprio Student::operator=(), in qualche modo che abbia senso. Il terzo modo è, come hai sottolineato, di usare un vettore di puntatori piuttosto che un vettore di oggetti. Ma poi devi gestire la loro allocazione e de-assegnazione.

P.S. L'altro caso in cui il compilatore non può generare operator= è quando la classe ha membri che sono riferimenti.

Problemi correlati