2015-06-07 10 views
5

I std::vectorimplementation di libC++ ha i seguenti overload di insert:libC++ differenza tra vettore :: insert sovraccarica

template <class _Tp, class _Allocator> 
typename vector<_Tp, _Allocator>::iterator 
vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) 
{ 
    pointer __p = this->__begin_ + (__position - begin()); 
    if (this->__end_ < this->__end_cap()) 
    { 
     __RAII_IncreaseAnnotator __annotator(*this); 
     if (__p == this->__end_) 
     { 
      __alloc_traits::construct(this->__alloc(), 
             _VSTD::__to_raw_pointer(this->__end_), __x); 
      ++this->__end_; 
     } 
     else 
     { 
      __move_range(__p, this->__end_, __p + 1); 
      const_pointer __xr = pointer_traits<const_pointer>::pointer_to(__x); 
      if (__p <= __xr && __xr < this->__end_) // [*] 
       ++__xr; 
      *__p = *__xr; 
     } 
     __annotator.__done(); 
    } 
    else 
    { 
     allocator_type& __a = this->__alloc(); 
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, __a); 
     __v.push_back(__x); 
     __p = __swap_out_circular_buffer(__v, __p); 
    } 
    return __make_iter(__p); 
} 

... e un simile, prendendo un riferimento rvalue:

template <class _Tp, class _Allocator> 
typename vector<_Tp, _Allocator>::iterator 
vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) 
{ 
    pointer __p = this->__begin_ + (__position - begin()); 
    if (this->__end_ < this->__end_cap()) 
    { 
     __RAII_IncreaseAnnotator __annotator(*this); 
     if (__p == this->__end_) 
     { 
      __alloc_traits::construct(this->__alloc(), 
             _VSTD::__to_raw_pointer(this->__end_), 
             _VSTD::move(__x)); 
      ++this->__end_; 
     } 
     else 
     { 
      __move_range(__p, this->__end_, __p + 1); 
      *__p = _VSTD::move(__x); 
     } 
     __annotator.__done(); 
    } 
    else 
    { 
     allocator_type& __a = this->__alloc(); 
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, __a); 
     __v.push_back(_VSTD::move(__x)); 
     __p = __swap_out_circular_buffer(__v, __p); 
    } 
    return __make_iter(__p); 
} 

Cosa è lo scopo del ramo contrassegnato con [*] nel primo sovraccarico? È richiesto dallo standard? Perché è assente nel secondo sovraccarico? Non sono riuscito a trovare il costrutto equivalente in libstdc++.

Edit: libstdc++solves lo stesso problema con la creazione di una copia temporanea.

+0

Grazie, ora sta benissimo :-) –

risposta

8

È una condizione per gestire il caso in cui l'elemento che si sta tentando di inserire esiste già nello vector.

Per spiegare questo, iniziamo con la definizione delle variabili utilizzate nella funzione.

  • __p è un puntatore alla posizione in cui si desidera inserire il nuovo elemento
  • __xr è un puntatore all'indirizzo dell'elemento che si desidera inserire

Il percorso di codice che sei chiedere informazioni viene eseguito quando lo vector ha una capacità sufficiente per inserire un elemento aggiuntivo (if (this->__end_ < this->__end_cap())). Inoltre, il punto di inserimento non è l'iteratore end() (if (__p == this->__end_) — viene eseguito il percorso else).

In questo caso, l'attuazione prima muove tutto nella gamma [__p, end()) una posizione ulteriormente — __move_range(__p, this->__end_, __p + 1);

Ma cosa succede se l'elemento si sta cercando di inserire faceva parte della gamma, che è appena stato spostato? In tal caso, è necessario incrementare il puntatore all'elemento da inserire. Questo è ciò che le righe seguenti fanno

if (__p <= __xr && __xr < this->__end_) 
    ++__xr; 

Il sovraccarico riferimento rvalue non sta facendo gli stessi controlli perché l'implementazione è consentito supporre che qualsiasi oggetto a cui un riferimento rvalue viene fatto riferimento univoco, in modo tentativo di eseguire una insert con un riferimento di rvalue a un elemento già esistente nello vector è un comportamento non definito.

Da N3337, §17.6.4.9/1 [res.on.arguments]

Ciascuno dei seguenti vale per tutti gli argomenti a funzioni definite nella libreria standard C++, se non diversamente specificato.
— ...
— Se un argomento di funzione si collega a un parametro di riferimento di rvalue, l'implementazione può assumere che questo parametro sia un riferimento univoco a questo argomento.

Ecco lo defect report e la motivazione per la clausola di cui sopra.

+0

Ottima risposta! Mi mancava il fatto che è possibile inserire qualcosa già inserito. – erenon

+0

@erenon Ricordo di aver letto una discussione da qualche parte che è possibile solo a causa di omissione. Niente nello standard ti dice che non ti è permesso inserire un elemento che è già nello stesso vettore, quindi sono richieste implementazioni per supportare questa possibilità. – Praetorian

+1

+1, spiegazione molto bella. Sono intenzionalmente infranto le regole sul commentare questo upvote perché ho scritto il codice che viene messo in discussione e le parole nello standard che supportano l'implementazione. –

Problemi correlati