C ++: возможно ли отсоединить указатель char * от объекта std :: string? - PullRequest
1 голос
/ 02 января 2012

Я использую тип std :: string для моих манипуляций со строками.

Однако иногда мне нужно сохранить необработанный указатель char *, даже после того, как исходный объект std :: string уничтожен (да, я знаю, что указатель char * ссылается на HEAP и должен в конечном итоге быть удален).

Тем не менее, похоже, что нет способа отсоединить необработанный указатель от строки или нет?

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

Спасибо.

РЕДАКТИРОВАТЬ

Люди, пожалуйста, не путайте отключение с копированием.Суть отсоединения заключается в том, чтобы строковый объект отказался от владения базовым буфером.Итак, если бы у строки был метод detach, ее семантика была бы примерно такой:

char *ptr = NULL;
{
  std::string s = "Hello world!";
  ptr = s.detach(); // May actually allocate memory, if the string is small enough to have been held inside the static buffer found in std::string.
  assert(s == NULL);
}
// at this point s is destroyed
// ptr continues to point to a valid HEAP memory with the "Hello world!" string in it.
...
delete ptr; // need to cleanup

Ответы [ 7 ]

5 голосов
/ 02 января 2012

Нет, невозможно отсоединить указатель, возвращенный std::string::c_str().

Решение: Сделайте копию строки только для чтения и убедитесь, что эта копия живет как минимум столько времени, сколько вам нужноуказатель char *Затем используйте c_str() для этой копии, и она будет действительна столько, сколько вы хотите.

Если это невозможно, вы также не сможете выпустить char*.И любая попытка обернуть этот указатель в конструкцию RAII, будет только заново изобретать части std :: string.

4 голосов
/ 02 января 2012

std::string выделяется через std:allocator (или параметр шаблона).Даже если бы вы могли отсоединить сырое хранилище, вам бы пришлось освободить его и через std::allocator.И вы, конечно, хотели бы, чтобы класс RAII делал это правильно.

К счастью, в стандартных библиотеках уже есть именно такой класс RAII.Она называется std::string.

. Ближайшая вещь к функции "отсоединения", следовательно, swap.Он отсоединяет ресурсы от строки и сохраняет их в форме, из которой они могут быть корректно освобождены позднее (т. Е. В другой строке).В C ++ 11 назначение перемещения также делает это.

std::string raii_for_ptr;
const char *ptr = NULL;
{
     std::string s = "Hello world!";
     raii_for_ptr.swap(s); // or raii_for_ptr = std::move(s)
     ptr = raii_for_ptr.c_str();
     assert(s == "");
}

// no need to cleanup

Если ваша цель состоит в том, чтобы создать для себя необходимость вызывать delete для чего-то, то (а) это абсурдно, а значит (б)) стандартные библиотеки вам не помогут.В любом случае вам, вероятно, понадобится delete[], а не delete.Но поскольку строки не (непосредственно) выделяются с помощью new, неуместно думать, что вы можете взять их память и освободить ее (напрямую) с помощью delete[].

Итак, если ваша реальная ситуация такова, что вынеобходимо передать некоторый ранее существующий API буфер, который будет освобожден с помощью delete[], тогда вам придется взять копию, как если бы вам нужно было передать некоторый ранее существующий API, буфер, который будет освобожден с помощью free.

1 голос
/ 02 января 2012

Вы можете скопировать вашу строку в новый массив char.

std::string s = "My string";
char *a = new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
1 голос
/ 02 января 2012

Используйте c_str(), чтобы скопировать строку в строку стиля C.А затем используйте strcpy()

0 голосов
/ 02 января 2012

U может использовать его следующим образом:

std::string str = "abcd";
char* cStr = str.c_str();

Спасибо ...:)

0 голосов
/ 02 января 2012

Поскольку вы всегда должны знать, кому принадлежит определенный раздел памяти, единственный способ изменить владельца строки - это скопировать ее. Самый простой способ сделать это - просто присвоить строку другой переменной std :: string. Если владение меняется очень часто (или вы просто не можете четко определить, какой конкретный объект является владельцем), вы захотите использовать другую реализацию строки (или оболочку для std :: string), которая поддерживает подсчет ссылок, поэтому приходится постоянно выделять новую память.

0 голосов
/ 02 января 2012

Вы можете использовать 2 вещи, в зависимости от того, что вам нужно.string :: c_str () скопирует символы в строку C, которую затем можно использовать для чего угодно.std :: data () вернет указатель на строку, но есть 2 проблемы: а) она не заканчивается на NULL, как строка C, и б) она исчезнет при удалении std :: string.Так что он не остается после удаления исходного объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...