У меня есть char* p, который указывает на строку с завершением \0. Как мне создать из него C++ string безопасным способом?
Вот небезопасная версия:
string foo()
{
char *p = get_string();
string str( p );
free( p );
return str;
}
Очевидным решением было бы попробовать-поймать - есть ли более простые способы?





Вы можете использовать shared_ptr из C++ 11 или Способствовать росту:
string
foo()
{
shared_ptr<char> p(get_string(), &free);
string str(p.get());
return str;
}
При этом используется очень специфическая функция shared_ptr, недоступная в auto_ptr или чем-либо еще, а именно возможность указывать настраиваемое средство удаления; в данном случае я использую free как средство удаления.
Ага - размотка на основе стека. В Modern C++ Design есть общее решение, но в этом случае вы можете использовать
struct Cleanup {
void* toFree;
Cleanup(void* toFree) : toFree(toFree) {}
~Cleanup() { free(toFree); }
private:
Cleanup(Cleanup&);
void operator=(Cleanup&);
};
Независимо от того, что происходит с вашим std :: string, free (toFree) будет вызываться, когда ваш объект Cleanup выходит за пределы области видимости.
Что ж, p не указывает на строку с завершающим нулем, если get_string() возвращает NULL; вот в чем проблема, поскольку конструкторы std::string, которые принимают указатель на строку C с завершением 0, не могут работать с NULL, которая является такой же строкой C с завершением 0, как и две дюжины бананов.
Итак, если get_string() - ваша собственная функция, а не функция библиотеки, то, возможно, вам следует убедиться, что она не может возвращать NULL. Например, вы можете позволить ему вернуть искомый std::string, поскольку он знает свое состояние. В противном случае я бы сделал это, используя Cleanup из этот ответ в качестве помощника, чтобы гарантировать, что p не может протечь (как предложил Мартин Йорк в комментарии):
string foo()
{
const char* p = get_string();
const Cleanup cleanup(p);
const std::string str(p != NULL ? p : "");
return str;
}
Кроме кода не компилируется (посмотрите на L ""). Это не исключение безопасно. Вы не гарантируете, что p будет выпущен.
Ах! Извините за это - я разрабатываю только для устройств на базе Windows CE, и там у нас есть только строки Unicode, поэтому префикс «L» вбивается мне в позвоночник, когда я пишу код. Теперь этот случай исправлен.
Уф! Теперь исчезла и эта утечка. Спасибо, что указали на это.
Обычно мы используем ScopeGuard для этих случаев:
string foo()
{
char *p = get_string();
ScopeGuard sg = MakeGuard(&free, p);
string str( p );
return str;
}
Могу я спросить, какого исключения вы ожидаете в своем примере?
На многих платформах (Linux, AIX) new или malloc никогда не выйдет из строя, и ваше приложение будет убито операционной системой, если у вас закончится память.
См. Эту ссылку: Что происходит, когда в Linux заканчивается память.
да, за исключением того, что мы обычно не используем Boost, но я могу создать такой класс сам. Спасибо