2013-05-15 4 views
8

Molti metodi all'interno della classe template vector prendono un riferimento const a value_type oggetti, per esempio:Qual è la logica del design dietro il metodo di ridimensionamento di std :: vector?

void push_back (const value_type& val); 

mentre resize prende il parametro value_type per valore:

void resize (size_type n, value_type val = value_type()); 

Come programmatore non esperto C++ Posso solo pensare a svantaggi con questa scelta (ad esempio se lo size_of(value_type) è abbastanza grande può verificarsi un sovraccarico dello stack). Quello che vorrei chiedere alle persone con più informazioni sulla lingua è quindi:

Qual è la logica del design dietro questa scelta?

+1

@ user814628 Questo non mi sembra giusto. L'unica volta che 'value_type val = value_type()' potrebbe non funzionare è se 'value_type' ha un costruttore di copie che ha preso un riferimento non const. –

+0

Non avevo mai notato prima che anche * fosse * un secondo parametro da ridimensionare (...)! Credo di aver imparato la mia unica cosa per il giorno e ora posso andare avanti fino a domani. :-P – aldo

risposta

9
void resize(size_type count, T value = T()); 

Questa funzione è stata rimossa da C++ 11.

C++ 11 ha two overloads di resize():

void resize(size_type count); 
void resize(size_type count, const value_type& value); 

che è praticamente semplice da capire. Il primo utilizza oggetti predefiniti di tipo value_type per riempire il vettore durante il ridimensionamento, il secondo assume un valore dal quale esegue le copie durante il ridimensionamento.

+0

Il mio male! Ero abbastanza pigro da guardare il prototipo di C++ 11 da [cplusplus] (http://www.cplusplus.com/reference/vector/vector/resize/) anziché dalla bozza standard, ed è evidente che ! – Massimiliano

+5

@Massimiliano: cplusplus è un sito non valido per le esercitazioni C++: anche le firme C++ 11 non sono corrette. Manca 'const &'. ** Preferisci [cppreference.com] (http://en.cppreference.com/w/cpp) su cplusplus.com ** – Nawaz

+0

Grazie per il suggerimento, inizierò a utilizzare cppreference. – Massimiliano

6

Questo sembra essere un difetto di progettazione, è stato risolto ora.

Citando STL defects 679

Lo standard C++ 98 specifica che una funzione membro solo dei contenitori passa il suo parametro (T) per valore invece che per riferimento const:

vuoto ridimensionamento (size_type sz, T c = T());

Questo fatto è stato discusso/discusso ripetutamente nel corso degli anni, la prima volta anche prima che il C++ 98 fosse ratificato. Il razionale per il passaggio di questo parametro per valore è stato:

Così che l'auto fa riferimento a dichiarazioni sono garantiti per lavoro, per esempio:

v.resize(v.size() + 1, v[0]); 

Tuttavia questa logica non è convincente come la firma per push_back è:

void push_back(const T& x); 

E push_back ha una semantica simile da ridimensionare (append). E push_back deve funzionare anche in caso di auto riferimento:

v.push_back(v[0]); // must work 

Il problema con il passaggio per valore T è che può essere significativamente più costoso di passaggio per riferimento. L'opposto è anche vero, tuttavia quando è vero è di solito molto meno drammatico (ad esempio per i tipi scalari).

Anche con la semantica del movimento disponibile, il passaggio di questo parametro in base al valore può essere costoso.Si consideri per esempio vector>:

std::vector<int> x(1000); 
std::vector<std::vector<int>> v; 
... 
v.resize(v.size()+1, x); 

Nel caso passaggio per valore, x viene copiato volta al parametro di ridimensionamento. E poi internamente, dato che il codice non può sapere in fase di compilazione di quanto ridimensiona il vettore, il x viene solitamente copiato (non spostato) una seconda volta dal parametro di ridimensionamento nella sua posizione corretta all'interno del vettore.

Con pass-by-const riferimento, il x nell'esempio precedente deve essere copiato solo una volta. In questo caso, x ha un costoso costruttore di copie e quindi qualsiasi copia che può essere salvata rappresenta un risparmio significativo.

Se siamo in grado di essere efficienti per push_back, dovremmo essere efficiente per il ridimensionamento pure. Il ridimensionamento che prende un parametro di riferimento è stato codificato e spedito nella libreria CodeWarrior senza segnalazioni di problemi di cui sono a conoscenza.

Proposta di delibera:

Change 23.3.3 [deque], p2:

class deque { 
    ... 
    void resize(size_type sz, const T& c); 

Change 23.3.3.3 [deque.capacity], p3:

void resize(size_type sz, const T& c); 

Change 23.3. 5 [lista], p2:

class list { 
    ... 
    void resize(size_type sz, const T& c); 

Ch ange 23.3.5.3 [list.capacity], p3:

void resize(size_type sz, const T& c); 

Change 23.3.6 [vettore], p2:

class vector { 
    ... 
    void resize(size_type sz, const T& c); 

Change 23.3.6.3 [vector.capacity], p11:

void resize(size_type sz, const T& c);