Pergunta

Estou fazendo algum trabalho de manutenção e encontrei algo como o seguinte:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

Eu sei que o uso de & s [0] seria seguro se fosse um vetor de std ::, mas isso é um uso seguro de STD :: string?

Foi útil?

Solução

A alocação de STD :: String não é garantida como contígua no padrão C ++ 98/03, mas o C ++ 11 obriga a ser. Na prática, nem eu nem Erva sutter Conheça uma implementação que não usa armazenamento contíguo.

Observe que o &s[0] É sempre garantido que o trabalho do C ++ 11, mesmo no caso de string de 0 comprimento. Não seria garantido se você fez str.begin() ou &*str.begin(), mas pelo &s[0] o padrão define operator[] Como:

Retorna: *(begin() + pos) E se pos < size(), caso contrário, uma referência a um objeto do tipo T com valor charT(); O valor referenciado não deve ser modificado

Continuando, data() é definido como:

Retornos: Um ponteiro p de tal modo que p + i == &operator[](i) para cada i dentro [0,size()].

(Observe os suportes quadrados nas duas extremidades da linha)


Perceber: Pré-padrão C ++ 0x não garantiu &s[0] Trabalhar com cordas de comprimento zero (na verdade, foi explicitamente indefinido comportamento), e uma revisão mais antiga dessa resposta explicou isso; Isso foi corrigido em rascunhos padrão posteriores, portanto a resposta foi atualizada de acordo.

Outras dicas

Tecnicamente, não, desde std::string não é necessário para armazenar seu conteúdo contíguo na memória.

No entanto, em quase todas as implementações (toda implementação da qual estou ciente), o conteúdo é armazenado de forma contígua e isso "funcionaria".

É seguro usar. Eu acho que a maioria das respostas estava correta uma vez, mas o padrão mudou. Citando do padrão C ++ 11, Basic_String Requisitos gerais [String.Require, 21.4.1.5, diz:

Os objetos do tipo char em um objeto Basic_String devem ser armazenados de forma contígua. Isto é, para qualquer objeto Basic_String s, a identidade &*(s.Begin () + n) == &*s.Begin () + n deve manter todos os valores de n tal que 0 <= n <s.size ().

Um pouco antes disso, diz que todos os iteradores são iteradores de acesso aleatório. Ambos os bits apóiam o uso da sua pergunta. (Além disso, o Stroustrup aparentemente o usa em seu livro mais novo;))

Não é improvável que essa mudança tenha sido feita no C ++ 11. Parece que me lembro que a mesma garantia foi adicionada para o vetor, que também obteve o muito útil dados() Ponteiro com esse lançamento.

Espero que ajude.

Os leitores devem observar que essa pergunta foi feita em 2009, quando o padrão C ++ 03 foi a publicação atual. Esta resposta é baseada nessa versão do padrão, em que std::strings são não garantido para utilizar armazenamento contíguo. Como essa pergunta não foi feita no contexto de uma plataforma específica (como o GCC), não faço suposições sobre a plataforma da OP - em particular, clima ou não, utilizou armazenamento contigioso para o string.

Jurídico? Talvez talvez não. Seguro? Provavelmente, mas talvez não. Bom código? Bem, não vamos lá ...

Por que não apenas fazer:

std::string s = str;

...ou:

std::string s(str);

...ou:

std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));

...ou:

std::string s;
s.assign( str, strLen );

?

O código pode funcionar, mas mais por sorte do que julgamento, faz suposições sobre a implementação que não são garantidas. Sugiro determinar a validade do código é irrelevante, enquanto é uma complicação inútil que é facilmente reduzida a apenas:

std::string s( str ) ;

ou se atribuir a um objeto STD :: String existente, apenas:

s = str ;

e então deixe o próprio std :: string determinar como alcançar o resultado. Se você vai recorrer a esse tipo de bobagem, também pode não estar usando o STD :: String e siga, pois está reintroduzindo todos os perigos associados a S Strings.

Isso é geralmente não Seguro, independentemente de a sequência de string interna ser armazenada na memória continuamente ou não. Pode haver muitos outros detalhes de implementação relacionados a como a sequência controlada é armazenada por std::string objeto, além da continuidade.

Um problema prático real com isso pode ser o seguinte. A sequência controlada de std::string Não é necessário que seja armazenado como uma string terminada zero. No entanto, na prática, muitas (a maioria?) As implementações optam por dimensionar o buffer interno por 1 e armazenar a sequência como uma corda terminada de zero de qualquer maneira, porque simplifica a implementação de c_str() Método: basta retornar um ponteiro ao buffer interno e você terminou.

O código que você citou em sua pergunta não faz nenhum esforço para terminação zero, os dados são copiados para o buffer interno. Muito possivelmente, simplesmente não sabe se a terminação zero é necessária para esta implementação de std::string. Muito possivelmente, depende do buffer interno ser preenchido com zeros após a chamada para resize, portanto, o caractere extra alocado para o terminador zero pela implementação é convenientemente predefinido para zero. Tudo isso é um detalhe de implementação, o que significa que essa técnica depende de algumas suposições bastante frágeis.

Em outras palavras, em algumas implementações, você provavelmente teria que usar strcpy, não memcpy Para forçar os dados na sequência controlada como essa. Enquanto estiver em outras implementações, você teria que usar memcpy e não strcpy.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top