Como retornar um std :: string.c_str ()

Eu tenho um método que retorna o ponteiro de char constante. Ele faz uso de um std::string e finalmente retorna seu ponteiro char c_str() .

 const char * returnCharPtr() { std::string someString; // some processing!. return someString.c_str(); } 

Eu tenho um relatório da ferramenta COVERITY que o acima não é um bom uso. Eu pesquisei e descobri que o ponteiro de caractere retornado seria invalidado assim que someString atinja sua destruição.

Considerando isso, como alguém resolve esse problema? Como devolver o ponteiro de char com precisão?

Retornar std::string resolveria esse problema. Mas eu quero saber se existe algum outro meio de fazer isso.

    O que acontece neste código é:

     const char * returnCharPtr() { std::string someString("something"); return someString.c_str(); } 
    1. instância de std::string é criada – é um object com duração de armazenamento automático
    2. apontador para a memory interna dessa string é retornado
    3. object someString é destruído e sua memory interna é limpa
    4. O chamador dessa function recebe um ponteiro pendente (ponteiro inválido) que produz um comportamento indefinido

    A melhor solução: retornar um object :

     std::string returnString() { std::string someString("something"); return someString; } 

    Em C ++, a coisa mais simples a fazer é retornar um std::string (que também é eficiente graças a otimizações como a semântica de movimento RVO e C ++ 11):

     std::string returnSomeString() { std::string someString; // some processing... return someString; } 

    Se você realmente precisa de um ponteiro C char* , você sempre pode chamar .c_str() no valor retornado, por exemplo

     // void SomeLegacyFunction(const char * psz) // .c_str() called on the returned string, to get the 'const char*' SomeLegacyFunction( returnSomeString().c_str() ); 

    Se você realmente quiser retornar um ponteiro char* da function, você pode alocar dinamicamente a memory de strings no heap (por exemplo, usando o new[] ), e retornar um ponteiro para isso:

     // NOTE: The caller owns the returned pointer, // and must free the string using delete[] !!! const char* returnSomeString() { std::string someString; // some processing... // Dynamically allocate memory for the returned string char* ptr = new char[someString.c_str() + 1]; // +1 for terminating NUL // Copy source string in dynamically allocated string buffer strcpy(ptr, someString.c_str()); // Return the pointer to the dynamically allocated buffer return ptr; } 

    Uma alternativa é fornecer um ponteiro de buffer de destino e o tamanho do buffer (para evitar overruns de buffer!) Como parâmetros de function:

     void returnSomeString(char* destination, size_t destinationSize) { std::string someString; // some processing... // Copy string to destination buffer. // Use some safe string copy function to avoid buffer overruns. strcpy_s(destination, destinationSize, someString.c_str()); } 

    Como esta questão é sinalizada C, faça isso:

     #define _POSIX_C_SOURCE 200809L #include  const char * returnCharPtr() { std::string someString; // some processing!. return strdup(someString.c_str()); /* Dynamically create a copy on the heap. */ } 

    Não esqueça de free() que a function retornou se não for mais usada.

    Bem, a COBERTURA está correta. A razão pela qual sua abordagem atual irá falhar é porque a instância de std::string você criou dentro da function só será válida enquanto esta function estiver rodando. Uma vez que o seu programa deixa o escopo da function, o destruidor do std :: string será chamado e esse será o fim da sua string.

    Mas se o que você quer é um C-string, que tal …

     const char * returnCharPtr() { std::string someString; // some processing!. char * new_string = new char[someString.length() + 1]; std::strcpy(new:string, someString.c_str()); return new_string; } 

    Mas espere … é quase exatamente como retornar um std::string , não é?

     std::string returnCharPtr() { std::string someString; // some processing!. return new_string; } 

    Isso irá copiar sua string para uma nova fora do escopo da function. Funciona, mas cria uma nova cópia da string.

    Graças a Return Value Optimization, isso não irá criar uma cópia (obrigado por todas as correções!).

    Então, outra opção é passar o parâmetro como um argumento, então você processa sua string em uma function mas não cria uma nova cópia. :

     void returnCharPtr(std::string & someString) { // some processing!. } 

    Ou, novamente, se você quiser C-Strings, você precisa estar atento para o comprimento da sua string:

     void returnCharPtr(char*& someString, int n) // a reference to pointer, params by ref { // some processing!. } 

    A melhor maneira seria retornar um std::string , que faz o gerenciamento automático de memory para você. Se, por outro lado, você realmente returnCharPtr retornar um const char* que aponta para alguma memory alocada por você de dentro de returnCharPtr , ele teria que ser liberado por outra pessoa explicitamente.

    Fique com std::string .

    Suas opções são:

    Retornar std::string

    Passe um buffer para returnCharPtr() que irá armazenar o novo buffer de caracteres. Isso requer que você verifique se o buffer fornecido é grande o suficiente para conter a cadeia.

    Crie uma nova matriz char dentro de returnCharPtr() , copie o buffer para o novo e retorne um ponteiro para ele. Isso exige que o chamador chame explicitamente delete [] em algo que não criou explicitamente com o new , ou coloque-o imediatamente em uma class de ponteiro inteligente. Essa solução seria melhorada se você retornasse um ponteiro inteligente, mas realmente faz mais sentido retornar um std::string diretamente.

    Escolha o primeiro; return std::string . É de longe a opção mais simples e mais segura.

    O problema é que someString é destruído no final da function e a function retorna o ponteiro para dados não existentes.

    Não retorne .c_str() da seqüência de caracteres que pode ser destruída antes de usar o ponteiro de char retornado.

    Ao invés de…

     const char* function() { std::string someString; // some processing! return someString.c_str(); } //... useCharPtr(function()); 

    usar

     std::string function() { std::string someString; // some processing! return someString; } //... useCharPtr(function().c_str()); 

    Você pode passar um ponteiro para sua string e fazer com que o método o manipule diretamente (isto é, evitando retornos)

     void returnCharPtr(char* someString) { // some processing! if(someString[0] == 'A') someString++; } 

    Se você tiver a liberdade de alterar o valor de retorno de returnCharPtr , altere-o para std::string . Esse será o método mais limpo para retornar uma string. Se você não puder, precisará alocar memory para a string retornada, copiá-la de std::string e retornar um ponteiro para a memory alocada. Você também precisa certificar-se de excluir a memory na function de chamada. Como o chamador será responsável por desalocar a memory, eu alteraria o valor de retorno para char* .

     char* returnCharPtr() { std::string someString; // some processing!. char* cp = new char[someString.length()+1]; strcpy(cp, someString.c_str()); return cp; } 

    Uma solução que não foi evocada nas outras respostas.

    Caso seu método seja membro de uma class, assim:

     class A { public: const char *method(); }; 

    E se a instância da class vai viver além da utilidade do ponteiro, você pode fazer:

     class A { public: const char *method() { string ret = "abc"; cache.push_back(std::move(ret)); return cache.last().c_str(); } private: vector cache; //std::deque would be more appropriate but is less known } 

    Dessa forma, os pointers serão válidos até a destruição de A

    Se a function não fizer parte de uma class, ela ainda poderá usar uma class para armazenar os dados (como uma variável static da function ou uma instância de class externa que pode ser referenciada globalmente, ou até mesmo um membro static de uma class). Mecanismos podem ser feitos para excluir dados após algum tempo, para não mantê-los para sempre.