HOWTO · C++

Devolver uma string a partir de uma função em C++

Este artigo demonstra como devolver uma string de uma função em C++

Nesta página

Numa função C++ comum, devolva std::string por valor. Assim, quem chama recebe uma string independente, e o C++ pode aplicar a otimização do valor de retorno quando possível. Use uma referência apenas para devolver um objeto existente cuja duração seja gerida noutro local; use um ponteiro ou uma string no estilo C apenas quando a interface exigir especificamente uma dessas formas. Os exemplos abaixo usam C++11 ou posterior.

Devolver uma string por valor

Devolver por valor é a opção padrão mais clara quando uma função cria ou transforma uma string. Quem chama recebe o seu próprio valor de string, que pode armazenar ou alterar de forma independente. Devolver uma variável local com nome costuma ser eficiente: o compilador pode construir o resultado diretamente no destino de quem chamou, através da otimização do valor de retorno nomeado. Se essa otimização não se aplicar, std::string pode ser movido. Nenhum desses comportamentos exige acrescentar std::move à instrução de retorno.

Execute este exemplo; o texto apresentado no código e na saída, incluindo “Hello, C++!”, permanece em inglês, como no original.

#include <iostream>
#include <string>

std::string makeGreeting() {
    std::string result = "Hello, C++!";
    return result;
}

int main() {
    std::string greeting = makeGreeting();
    std::cout << greeting << '\n';
}

O tipo de retorno da função é std::string, e return result; devolve o valor local. A variável local deixa de existir quando a função termina, mas a string devolvida continua disponível para quem chamou. Em geral, devolver por valor é mais simples e seguro do que gerir separadamente a propriedade de uma string alocada dinamicamente.

Devolver uma referência a uma string existente

Uma referência devolvida é um alias de um objeto que já existe; não cria uma string nova. Isto pode ser útil quando uma função seleciona ou expõe uma string pertencente a um objeto com uma duração mais longa. Quem chama vê o mesmo objeto, pelo que as alterações feitas através de uma referência não constante afetam o original. Use uma const std::string& quando quem chama precisar de ler o valor sem o modificar.

O objeto referenciado tem de continuar a existir durante todo o período em que a referência devolvida for usada. Nunca devolva uma referência a uma variável local: esta é destruída quando a função termina, deixando quem chamou com uma referência pendente. Só é seguro devolver um parâmetro de referência se quem chamou mantiver o argumento vivo, como no exemplo seguinte. O código e o texto apresentado, “Existing string”, permanecem em inglês, como no original.

#include <iostream>
#include <string>

const std::string& sameString(const std::string& value) {
    return value;
}

int main() {
    std::string original = "Existing string";
    const std::string& alias = sameString(original);
    std::cout << alias << '\n';
}

Devolver uma string por ponteiro

Devolver um ponteiro pode representar acesso opcional ou seguir uma interface existente, mas torna a duração e a propriedade parte do contrato. Prefira devolver o endereço de uma string existente apenas se ela continuar viva durante todo o período de utilização do ponteiro. Documente quem é responsável pelo objeto e se o ponteiro pode ser nulo.

Não aloque uma std::string com new só para a devolver. Isso obriga quem chama a lembrar-se de libertar a memória com delete e dificulta o tratamento de retornos antecipados e erros. Para uma string criada de novo, devolva por valor. O exemplo seguinte aponta para um objeto existente e mantém-no vivo enquanto o ponteiro é usado. O código e o texto apresentado, “Hello through a pointer”, permanecem em inglês, como no original.

#include <iostream>
#include <string>

const std::string* findGreeting(const std::string& value) {
    return &value;
}

int main() {
    std::string greeting = "Hello through a pointer";
    const std::string* result = findGreeting(greeting);
    if (result != nullptr) {
        std::cout << *result << '\n';
    }
}

A função não assume a propriedade de value. Quem chamou não deve manter o ponteiro devolvido depois de a string referenciada ser destruída.

Usar std::move apenas quando for útil

std::move é uma conversão que permite uma operação de movimentação; não move os dados por si só. Numa instrução de retorno, escrever return std::move(local); é geralmente desnecessário. Isso pode impedir a otimização do valor de retorno nomeado e, possivelmente, substituir a construção direta por uma movimentação. Prefira return local; para um resultado local e deixe a linguagem e o compilador escolherem a otimização aplicável.

As movimentações explícitas são úteis ao transferir um objeto que não pode ser movido automaticamente, como um membro que tem de ser retirado de um objeto com uma duração mais longa. Isso altera o objeto de origem, por isso só o faça quando o estado anterior já não for necessário. Não acrescente std::move apenas para dar a impressão de que o retorno será mais rápido.

Devolver uma string no estilo C com char*

Uma string no estilo C é uma sequência de caracteres terminada em nulo, não um std::string. Se uma API exigir um ponteiro para caracteres e o resultado for texto fixo, devolva const char* a apontar para um literal de string. Os literais de string têm duração de armazenamento estática, pelo que o ponteiro continua válido durante todo o programa. Aqui, const char* significa um ponteiro para caracteres constantes: não é possível modificar esses caracteres através do ponteiro, mas o próprio ponteiro não é constante e pode ser reatribuído. Isto é diferente de char* const, que é um ponteiro constante para caracteres modificáveis. O literal de string não deve ser modificado.

O código e o texto apresentado, “Hello from C-style text”, permanecem em inglês, como no original.

#include <iostream>

const char* greeting() {
    return "Hello from C-style text";
}

int main() {
    std::cout << greeting() << '\n';
}

Não devolva um ponteiro para um vetor local de caracteres, que deixa de existir quando a função retorna, nem um ponteiro para uma std::string local. O resultado de c_str() depende do tempo de vida do objeto std::string e pode ser invalidado por operações que modificam essa string. Se quem chama precisar de um resultado independente e modificável, devolva std::string.