É razoável usar std :: basic_string como um buffer contíguo ao direcionar C ++ 03?

Eu sei que, em C ++ 03, tecnicamente, o modelo std::basic_string não precisa ter memory contígua. No entanto, estou curioso para saber quantas implementações existem para os compiladores modernos que realmente aproveitam essa liberdade. Por exemplo, se alguém quiser usar basic_string para receber os resultados de alguma API C (como no exemplo abaixo), parece bobagem alocar um vetor apenas para transformá-lo em uma string imediatamente.

Exemplo:

 DWORD valueLength = 0; DWORD type; LONG errorCheck = RegQueryValueExW( hWin32, value.c_str(), NULL, &type, NULL, &valueLength); if (errorCheck != ERROR_SUCCESS) WindowsApiException::Throw(errorCheck); else if (valueLength == 0) return std::wstring(); std::wstring buffer; do { buffer.resize(valueLength/sizeof(wchar_t)); errorCheck = RegQueryValueExW( hWin32, value.c_str(), NULL, &type, &buffer[0], &valueLength); } while (errorCheck == ERROR_MORE_DATA); if (errorCheck != ERROR_SUCCESS) WindowsApiException::Throw(errorCheck); return buffer; 

Eu sei que código como este pode reduzir um pouco a portabilidade porque implica que std::wstring é contíguo – mas eu estou querendo saber o quão não portável é esse código. Em outras palavras, como os compiladores podem tirar proveito da liberdade que permite a memory não contígua?


EDIT: eu atualizei esta questão para mencionar C + + 03. Os leitores devem observar que, ao segmentar o C ++ 11, o padrão agora exige que o basic_string seja contíguo, portanto, a pergunta acima não é um problema ao segmentar esse padrão.

Eu consideraria bastante seguro assumir que std :: string aloca seu armazenamento contiguamente.

No momento, todas as implementações conhecidas de std::string alocam o espaço de forma contígua.

Além disso, o rascunho atual de C ++ 0x ( N3000 ) [Edit: Warning, link direto para PDF grande] requer que o espaço seja alocado contiguamente (§21.4.1 / 5):

Os objects tipo char em um object basic_string devem ser armazenados contiguamente. Isto é, para qualquer object basic_string s, a identidade & * (s.begin () + n) == & * s.begin () + n deve ser válida para todos os valores de n tais que 0 <= n

Assim, as chances de uma implementação atual ou futura de std::string usando armazenamento não contíguo são essencialmente nulas.

Um tempo atrás, houve uma questão sobre ser capaz de escrever para o armazenamento de um std::string como se fosse uma matriz de caracteres, e dependia se o conteúdo de um std::string fosse contíguo:

  • É legal escrever para std :: string?

Minha resposta indicou que de acordo com algumas fonts bem conceituadas (Herb Sutter e Matt Austern) o padrão C ++ atual requer std::string para armazenar seus dados contíguos sob certas condições (uma vez que você chama str[0] assumindo str é um std::string ) e que esse fato praticamente força a mão de qualquer implementação.

Basicamente, se você combinar as promises feitas por string::data() e string::operator[]() você conclui que &str[0] precisa retornar um buffer contíguo. Portanto, Austern sugere que o comitê apenas torne isso explícito, e aparentemente é isso que acontecerá no padrão 0x (ou eles estão chamando de padrão 1x agora?).

Então, estritamente falando, uma implementação não tem que implementar std::string usando armazenamento contíguo, mas tem que fazê-lo praticamente sob demanda. E o seu código de exemplo faz exatamente isso passando em &buffer[0] .

Links:

  • Comentário de Herb Sutter
  • Relatório de Defeitos da Biblioteca Padrão C ++ de Matt Austern
  • anterior SO resposta

O resultado é indefinido e eu não faria isso. O custo de ler em um vetor e depois converter em uma string é trivial nos heaps modernos em c ++. VS o risco de seu código morrer no Windows 9

também, não precisa de um const_cast no & buffer [0]?

Edit: Você quer chamar &buffer[0] , não buffer.data() , porque [] retorna uma referência não- const e notifica o object que seu conteúdo pode mudar inesperadamente.


Seria mais limpo fazer o buffer.data() , mas você deveria se preocupar menos com a memory contígua do que com a memory compartilhada entre as estruturas. implementações de string podem e esperam ser informadas quando um object está sendo modificado. string::data requer especificamente que o programa não modifique o buffer interno retornado.

MUITO altas chances de que alguma implementação criará um buffer para todas as seqüências de caracteres não inicializadas, além de ter o tamanho definido como 10 ou qualquer outra coisa.

Use um vector ou até mesmo um array com o new[] / delete[] . Se você realmente não pode copiar o buffer, inicialize legalmente a string para algo único antes de alterá-lo.

Claro, alocar um vetor aqui é bobagem. Usar std :: wstring aqui também não é sábio. É melhor usar uma matriz de caracteres para chamar o winapi. construa uma corda ao retornar o valor.