Еще один обучающий момент в C ++: возвращение строк из функций - PullRequest
14 голосов
/ 19 июля 2010

У меня есть несколько основных вопросов о C ++.Рассмотрим следующий код, в котором я пытаюсь вернуть строку.

const std::string&
NumberHolder::getValueString() {
    char valueCharArray[100];
    sprintf_s(valueCharArray,"%f",_value);
    std::string valueString(valueCharArray);
    return valueString;
}

Я пытаюсь вернуть строку со значением члена класса с именем _value.Однако я получаю предупреждение, что пытаюсь вернуть указатель на локальную переменную.Это конечно плохо.Если я достаточно понимаю C ++ на этом этапе, это означает, что к указателю, который я передаю обратно, уже будет вызвано удаление, когда кто-то попытается его использовать.Поэтому я изменяю:

const std::string&
NumberHolder::getValueString() {
    char valueCharArray[100];
    sprintf_s(valueCharArray,"%f",_value);
    std::string valueString = new std::string(valueCharArray);
    return (*valueString);
}

Это должно создать указатель на стек, который будет существовать вне этой функции.Здесь есть две проблемы: 1) он все равно не компилируется, и я не понимаю, почему (error = не может преобразовать из 'std :: string *' в 'std :: basic_string <_Elem, _Traits, _Ax>') и 2) Это похоже на потенциальную утечку памяти, потому что я полагаюсь, что кто-то еще вызовет удаление на этом парне.Какой шаблон я должен использовать здесь?

Ответы [ 4 ]

26 голосов
/ 19 июля 2010

Вы побеждаете смысл наличия std::string, выделяя его в кучу!

Просто верните его по значению, как это:

std::string NumberHolder::getValueString()
{ 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    return std::string(valueCharArray); 
} 

Почти каждый компилятор в настоящее время будет выполнять оптимизацию возвращаемого значения (RVO) в операторе возврата, поэтому копирование не должно производиться. Учтите следующее:

NumberHolder holder;
// ...
std::string returnedString = holder.getValueString();

При использовании RVO компилятор сгенерирует код для вышеприведенной реализации NumberHolder::getValueString(), такой, что std::string создается в месте returnedString, поэтому копии не нужны.

16 голосов
/ 19 июля 2010

Вы получаете это предупреждение, потому что вы возвращаете ссылку на локальную строку, а не копию локальной строки.Как только функция возвращается, локальная строка уничтожается, а ссылка, которую вы вернули, недействительна.Таким образом, вам нужно вернуть строку по значению, а не по ссылке:

std::string NumberHolder::getValueString()
3 голосов
/ 19 июля 2010

Ваша первая попытка верна, если вы возвращаете временную переменную, но связываете ее в константной ссылке.

const std::string NumberHolder::getValueString(){}

const std::string& val = NumberHolder::getValueString();

const .Но ваша вторая попытка опасна, в зависимости от того, кого еще нужно удалить.

0 голосов
/ 19 июля 2010
std::string *valueString = new std::string(valueCharArray);

Вам нужно создать переменную-указатель для хранения результата из new, так как он возвращает указатель. Тем не менее, идеальным решением было бы просто вернуть значение:

std::string NumberHolder::getValueString() {
    ...
    return std::string(valueCharArray);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...