2011-02-09 11 views
11

I contenitori STL richiedono che i valori memorizzati siano costruibili e assegnabili alla copia. const T non è ovviamente un tipo assegnabile a nessun T, ma ho provato ad usarlo (solo curioso) e ho scoperto che si compila e, inoltre, si comporta come un tipo assegnabile.VC++ consente di utilizzare i tipi const per i contenitori STL. Perché?

vector<const int> v(1); 
v[0] = 17; 

gestisce questo successo in Visual Studio 2008 e assegna v [0] per 17.

+1

Non solo: VS 2010 consente di * assegnare nuovi valori * a 'v [0]'. Provalo! –

+1

Sono curioso di ciò che VC fornisce per typeid (vector :: value_type) .name() (e lo si confronta con typeid (vector :: value_type) .name() o demanglo esso). –

+0

Uno e lo stesso: 'int'. –

risposta

1

Questo semplicemente non dovrebbe funzionare. Al §23.1 ¶ 3 è specificato, come hai detto, che gli oggetti memorizzati in un contenitore devono essere CopyConstructible (come specificato al §20.1.3) e Assignable.

I requisiti Assignable per un tipo T sono che, essendo t e u di tipo T, si può fare:

t = u 

avere un T& come valore di ritorno e t equivalente a u come postcondition. (§23.1 ¶4)

Così, const tipi sono chiaramente non Assignable, dal momento che facendo t = u solleverebbe un errore di compilazione (§7.1.5.1 ¶5).

Suppongo che si tratti di un bug nell'implementazione di Microsoft. g ++ su Linux emette il tipico errore di modello di linee da 25 kajillion se si tenta anche di istanziare un vector<const int> (testato con e senza il flag -std=c++0x, per ogni evenienza).

A proposito, questo è anche spiegato in dettaglio in questo IBM FAQ.


In teoria, come ha detto @James McNellis, il compilatore non è tenuto a saltare sul instantiation vettore (se si tratta di qualcosa di indefinito comportamento può accadere - tra cui tutto funziona bene); tuttavia, nella dichiarazione di assegnazione c'è una violazione dello standard che dovrebbe produrre un errore di compilazione.

In effetti, il membro operator[] restituisce un vector<const int>::reference; quello è richiesto per essere un lvalue di T (§23.1 ¶5 tabella 66); poiché T è di tipo const, sarà un valore di const. Quindi cadiamo in (§7.1.5.1 ¶5), che definisce il codice che tenta di eseguire un'assegnazione ad un elemento const come "mal formato", e ciò richiede un errore di compilazione o almeno un avvertimento, perché l'assegnazione a - const è una regola diagnosticabile (§1.4 ¶1-2) (non è stata specificata alcuna istruzione "non è richiesta alcuna diagnostica").


montaggio finale

In realtà, @James McNellis è giusto; una volta che hai invocato il comportamento non definito istanziando vector<const int>, le normali regole smettono di avere valore, quindi l'implementazione è ancora conforme agli standard qualunque cosa faccia, inclusa la rimozione dello const dal tipo di elemento o la generazione dei soliti demoni nasali.

+1

Un più facile il modo per farlo funzionare sarebbe un tratto di tipo remove_const (questo tratto esatto dovrebbe essere in 0x, ma forse con un nome diverso) piuttosto che mutabile. –

+0

@Fred Nurk: molto probabilmente è come hai detto tu. In realtà penso che la cosa 'mutabile' che ho scritto fosse una brainfart, dato che 'mutable' è messo su campi di classe non-'const' (§7.1.2 ¶8) per lasciarli essere modificati dai metodi' const', e questo non ha nulla a che fare con la rimozione di 'const' da tipi di template. –

+0

Questo non è un bug nell'implementazione. Il programma dell'OP esibisce un comportamento indefinito. –

12

Questo non è un bug nell'implementazione come altri hanno suggerito.

La violazione dei requisiti di una libreria di libreria standard C++ non rende il tuo programma mal formato, produce un comportamento non definito.

Hai violato il requisito che il tipo di valore archiviato in un contenitore deve essere costruibile e assegnabile alla copia (i tipi const non sono assegnabili, ovviamente), pertanto il tuo programma presenta un comportamento non definito.

La lingua applicabile dal ++ standard C può essere trovato in C++ 03 17.4.3.6 [lib.res.on.functions]:

In alcuni casi (funzioni di sostituzione, funzioni di gestione, operazioni su tipi utilizzati per creare un'istanza di componenti modello di libreria standard), la libreria standard C++ dipende dai componenti forniti da un programma C++. Se questi componenti non soddisfano i loro requisiti, lo standard non pone requisiti per l'implementazione.

In particolare, gli effetti sono indefiniti nei seguenti casi:

...

  • per i tipi utilizzati come argomenti di template quando un'istanza di un componente di modello, se le operazioni sul tipo non implementano la semantica della sottoclavi dei Requisiti applicabili.

L'implementazione di Visual C++ Standard Library può fare qualsiasi cosa con questo codice, tra cui la rimozione di silenzio o ignorare il const-qualificazione, ed è ancora standard conforme.

+3

Nella mia più umile opinione, la rimozione silenziosa delle qualifiche qui è davvero, davvero brutta. –

+0

La rimozione delle qualifiche può effettivamente infrangere la perversione, ma continua a conformarsi agli standard del codice.È possibile scrivere una classe che dispone di un operatore di assegnazione copie con qualifica che garantisce 't == u' dopo' t = u' _e_ un operatore di assegnazione copia con qualifica non codificata che non garantisce la post-condizione. In questo modo, 'const T' sarebbe assegnabile, ma' T' non lo sarebbe. Non riesco a immaginare alcun caso valido per questo, e se vedessi un codice del genere probabilmente piangerei. –

+0

Poiché lo standard definisce "assegnabile", sembra che la post-condizione sia che t e u sono equivalenti. - BTW, è C++ 0x andando a rimuovere il requisito di assegnazione? Non riesco più a vederlo nella bozza e sarebbe logico che le operazioni che non richiedono l'assegnazione funzionino. – UncleBens

Problemi correlati