Еще один момент обучения С++: возвращение строк из функций
У меня есть некоторые основные вопросы о С++. Рассмотрим следующий код, в котором я пытаюсь вернуть строку.
const std::string&
NumberHolder::getValueString() {
char valueCharArray[100];
sprintf_s(valueCharArray,"%f",_value);
std::string valueString(valueCharArray);
return valueString;
}
Я пытаюсь вернуть строку со значением члена класса с именем _value. Однако я получаю предупреждение о том, что я пытаюсь передать указатель на локальную переменную. Это, конечно, плохо. Если я понимаю С++ достаточно на этом этапе, это означает, что указатель, который я передаю, уже будет иметь удаление, вызванное им, к тому времени, когда кто-то попытается его использовать. Поэтому я изменяю:
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) Это похоже на потенциальную утечку памяти, потому что я зависим от кого-то другого, чтобы называть этого парня. Какую модель мне следует использовать здесь?
Ответы
Ответ 1
Вы побеждаете точку с std::string
, выделив ее в куче!
Просто верните его по значению, как это:
std::string NumberHolder::getValueString()
{
char valueCharArray[100];
sprintf_s(valueCharArray,"%f",_value);
return std::string(valueCharArray);
}
Почти каждый компилятор теперь сделает оптимизацию возвращаемого значения (RVO) в инструкции return, поэтому никаких копий не следует делать. Рассмотрим следующее:
NumberHolder holder;
// ...
std::string returnedString = holder.getValueString();
С RVO компилятор будет генерировать код для вышеупомянутой реализации NumberHolder::getValueString()
, так что std::string
создается в месте returnedString
, поэтому копии не нужны.
Ответ 2
Вы получаете это предупреждение, потому что вы возвращаете ссылку на локальную строку, а не копию локальной строки. Как только функция вернется, локальная строка будет уничтожена, а возвращаемая вами ссылка недействительна. Таким образом, вам нужно вернуть строку по значению, а не по ссылке:
std::string NumberHolder::getValueString()
Ответ 3
Ваша первая попытка правильная, если вы возвращаете временную переменную, но привязываете ее в константной ссылке.
const std::string NumberHolder::getValueString(){}
const std::string& val = NumberHolder::getValueString();
const. Но ваша вторая попытка опасна, в зависимости от кого-то еще, чтобы удалить.
Ответ 4
std::string *valueString = new std::string(valueCharArray);
Вам нужно будет создать переменную-указатель, чтобы сохранить результат из new
, так как он возвращает указатель. Однако идеальным решением было бы просто вернуться по значению:
std::string NumberHolder::getValueString() {
...
return std::string(valueCharArray);
}