2015-12-08 21 views
15

In 11 array, dynarray, string e vector tutti avuto il metodo C++ data cui:Perché non std :: string.data() fornisce un carattere mutabile *?

ritorni puntatore alla matrice sottostante che funge da elemento di memorizzazione. Il puntatore è tale che l'intervallo [data(); data() + size()) è sempre un intervallo valido, anche se il contenitore è vuoto. [Source]

Questo metodo è fornito in un mutevole e const versione per tutti i contenitori applicabili, ad esempio:

T* vector<T>::data(); 
const T* vector<T>::data() const; 

Tutti i contenitori applicabili, cioè, tranne string che only provides the const version:

const char* string::data() const; 

Che cosa è successo qui? Perché lo string si è trasformato in shortchanged, quando char* string::data() sarebbe stato così utile?

+10

È stato discusso ed è registrato come un problema, dettagli [qui] (http://cplusplus.github.io/LWG/lwg-active.html#2391). – Alper

+0

Fa: '& s [0]', per stringhe non vuote. –

+0

Penso che se hai bisogno di modificare la stringa tramite 'data', probabilmente stai cercando' vector ', invece. Ci sono alcune eccezioni, però. – edmz

risposta

7

La risposta breve è che fornisce lo char* string::data() method. Che è vitale per il modo simile data function, quindi per accedere mutabile al sottostante C-String ora posso fare questo:

auto foo = "lorem ipsum"s; 

for(auto i = data(foo); *i != '\0'; ++i) ++(*i); 

per scopi storici che vale la pena che racconta lo sviluppo string s', che sta costruendo su: In accesso al buffer sottostante string s' è reso possibile possibile da un nuovo requisito che è elementi sono memorizzati in modo contiguo tale che per ogni dato string s:

&*(s.begin() + n) == &*s.begin() + n per qualsiasi n in [0, s.size()) o, analogamente, un puntatore a s[0] può essere passato a funzioni che prevedono un puntatore al primo elemento di un array CharT[].

accesso Mutevole a questa nuova richiesto sottostante C-String è ottenibile con vari metodi, ad esempio: &s.front(), &s[0], o &*s.first() Ma torniamo alla domanda iniziale che eviterebbe l'onere di utilizzare una di queste opzioni: Perché non è stato fornito l'accesso al buffer sottostante di string sotto forma di char* string::data()?

Per rispondere è importante notare che T* array<T>::data() e T* vector<T>::data() erano un'aggiunta richiesta da . Nessun ulteriore requisito è stato richiesto da rispetto ad altri contenitori contigui come deque. E certamente non c'era un requisito aggiuntivo per string, infatti il ​​requisito che string was contiguous era nuovo a . Prima che esistesse questo const char* string::data(). Anche se era esplicitamente non garantito da punta a qualsiasi tampone sottostante, era l'unico modo per ottenere un const char* da un string:

La matrice restituita non è richiesto di essere terminazione null.

Ciò significa che string non era "imbrogliati" in transizione s' a data di accesso, semplicemente non era incluso quindi solo il constdata accesor che string precedentemente posseduta persisteva. Esistono naturally occurring examples in C++11's implementation che richiedono la scrittura direttamente nel buffer sottostante di uno string.

13

Penso che questa limitazione provenga dai giorni (pre-2011) in cui std::basic_string non doveva memorizzare il buffer interno come array di byte contigui.

Mentre tutti gli altri (std::vector e simili) dovevano memorizzare i loro elementi come sequenza contigua per lo standard 2003; così data potrebbe facilmente tornare mutabile T*, perché non c'era alcun problema con iterazioni, ecc

Se std::basic_string tornasse mutabile char*, ciò implicherebbe che si può trattare che char* come un C-string e preforme C-stringa valida operazioni come strcpy, che si sarebbero facilmente trasformate in comportamenti non definiti, erano la stringa non allocata in modo contiguo.

lo standard C++ 11 ha aggiunto la regola che basic_string deve essere implementata come array di byte contigui. inutile dire che puoi aggirare questo problema usando il vecchio trucco di &str[0].

+2

I andrebbe oltre e direbbe che fornire un metodo 'dati()' mutabile vanificherebbe l'incapsulamento dell'oggetto 'stringa' incoraggiando gli sviluppatori a usarlo come buffer di byte, quindi sarebbe un passo retrogrado –

+0

diciamo che proviene dalla restrizione pre-C++ 11, ma poiché 'string :: data' è stata introdotta come parte del C++ 11, dove e il requisito contiguo era già presente, perché non fornire anche la stringa' char * :: data() 'come parte di C++ 11? –

+1

secondo qui: http://www.cplusplus.com/reference/string/string/data/ 'std :: string :: data' esisteva già da C++ 98. parla anche dello stesso problema che ho presentato qui. –