безопасное создание std :: string из char * - PullRequest
10 голосов
/ 29 октября 2008

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

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

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

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

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

Ответы [ 5 ]

25 голосов
/ 29 октября 2008

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

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

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

3 голосов
/ 29 октября 2008

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

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

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

1 голос
/ 29 октября 2008

Ну, 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;
}
1 голос
/ 29 октября 2008

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

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

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

0 голосов
/ 29 октября 2008

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

string foo()
{
  char *p = get_string();
  ScopeGuard sg = MakeGuard(&free, p);
  string str( p );
  return str;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...