Создайте std::string из char * безопасным способом

У меня есть char* p, который указывает на строку \0 -terminated. Как создать С++ string из него безопасным способом?

Вот небезопасная версия:

string foo()
{
  char *p = get_string();

  string str( p );
  free( p );
  return str;
}

Очевидным решением было бы попытаться поймать - все более простые способы?

Ответ 1

Вы можете использовать shared_ptr из С++ 11 или Boost:

string
foo()
{
    shared_ptr<char> p(get_string(), &free);
    string str(p.get());
    return str;
}

Это использует очень специфическую особенность shared_ptr, недоступную в auto_ptr или что-то еще, а именно возможность указать пользовательский делектор; в этом случае я использую free в качестве дебетера.

Ответ 2

Могу ли я спросить вас, какое исключение вы ожидаете в своем примере?

На многих платформах (Linux, AIX) новые или malloc никогда не потерпят неудачу, и ваше приложение будет убито os, если у вас закончится нехватка памяти.

Смотрите эту ссылку: Что происходит, когда в Linux заканчивается память.

Ответ 3

Yup - разматывание на основе стека. Современный дизайн С++ имеет общее решение, но в этом случае вы можете использовать

struct Cleanup {
        void* toFree;
        Cleanup(void* toFree) : toFree(toFree) {}
        ~Cleanup() { free(toFree); }
    private:
        Cleanup(Cleanup&);
        void operator=(Cleanup&);
};

Независимо от того, что происходит с вашим std::string, вызывается бесплатный (toFree), когда объект Cleanup выходит из области действия.

Ответ 4

Ну, p не указывает на строку с нулевым завершением, если get_string() возвращает NULL; что проблема здесь, так как конструкторы std::string, которые берут указатель на строку C с 0-концами, не могут иметь дело с NULL, который является такой же строкой C с 0-концевой строкой, что и два десятка бананов.

Итак, если get_string() - ваша собственная функция, а не библиотечная функция, то, возможно, вы должны убедиться, что она не может вернуть NULL. Вы могли бы, например, позволить ему вернуть искомый std::string сам, поскольку он знает его собственное состояние. В противном случае я сделал бы это, используя Cleanup from этот ответ в качестве помощника, чтобы гарантировать, что p не может протекать (как предложил Мартин Йорк в комментарии ):

string foo()
{
    const char* p = get_string();
    const Cleanup cleanup(p);
    const std::string str(p != NULL ? p : "");

    return str;
}

Ответ 5

Мы обычно используем ScopeGuard для этих случаев:

string foo()
{
  char *p = get_string();
  ScopeGuard sg = MakeGuard(&free, p);
  string str( p );
  return str;
}