.c_str () странность? Данные изменяются без рифмы или причины? - PullRequest
3 голосов
/ 07 декабря 2009

У меня есть эта простая функция:

const wchar_t *StringManager::GetWCharTStar(int stringId)
{
    std::wstring originalString = StringManager::GetString(stringId);
    const wchar_t *retStr = originalString.c_str();
    return retStr;
}

Во второй строке этой функции у меня есть правильный wchar_t *. Однако когда я возвращаюсь, данные переключаются на ненужные данные. Между ними нет функций. Что дает?!

Ответы [ 5 ]

11 голосов
/ 07 декабря 2009

originalString размещается в стеке. Метод .c_str () просто возвращает указатель на некоторую непрерывную внутреннюю память объекта wstring. Когда функция возвращается, originalString выходит из области видимости и уничтожается, поэтому возвращаемое вами значение указателя указывает на удаленную память.

Если вам нужно сделать это, вы должны сделать копию данных в памяти, которую вы выделяете с помощью new или malloc (), а затем вызывающая сторона должна удалить / освободить () эту память.

5 голосов
/ 07 декабря 2009

Вы возвращаете указатель на временный. Когда originalString выходит из области видимости, данные, на которые указывает указатель, будут удалены.

3 голосов
/ 07 декабря 2009

std::wstring originalString; - это локальная переменная внутри тела вашей GetWCharTStar функции.

Как только вы выходите из области действия функции GetWCharTStar(), эта локальная переменная уничтожается, и возвращаемый вами указатель становится недействительным.

Следующий код может в конечном итоге работать:

const wchar_t *StringManager::GetWCharTStar(int stringId)
{
    const std::wstring& originalString = StringManager::GetString(stringId);
    const wchar_t *retStr = originalString.c_str();
    return retStr;
}

При условии StringManager::GetString() возвращает ссылку:

const std::wstring& StringManager::GetString(int stringId);

Однако это все еще рискованно, поскольку предполагается, что строки, управляемые вашим классом StringManager, никогда не будут перемещены в память. Например, если StringManager реализован с помощью std::vector, тогда, как только вектору потребуется расширить, его предыдущее содержимое копируется в другое место в более крупном блоке памяти, и вы в конечном итоге удерживаете ссылку на объект, который там больше нет.

Другими словами, избегать возврата дескрипторов внутренних данных .

1 голос
/ 07 декабря 2009

Предыдущие ответы в основном правильные, за исключением одной маленькой детали. Вы не возвращаете указатель на уничтоженный объект, вы возвращаете указатель , принадлежащий уничтоженному объекту. Когда этот объект был уничтожен, объект, на который указывал ваш указатель, также был уничтожен.

0 голосов
/ 07 декабря 2009

Это часто задаваемые вопросы. Вы возвращаете указатель на освобождаемый объект (объект originalString) до того, как вы его фактически используете.

...