string.c_str () освобождение необходимо? - PullRequest
32 голосов
/ 13 января 2012

Мой код преобразует строки C ++ в строки CStrings довольно часто, и мне интересно, будет ли исходная строка размещаться в стеке, будет ли CString размещаться также в стеке? Например:

string s = "Hello world";
char* s2 = s.c_str();

Будет ли s2 выделяться в стеке или в куче? Другими словами, мне нужно будет удалить s2?

И наоборот, если у меня есть этот код:

string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();

Будет ли s2 теперь в куче, так как его источник был в куче?

Чтобы уточнить, когда я спрашиваю, находится ли s2 в куче, я знаю, что указатель находится в стеке. Я спрашиваю, будет ли на что он указывает находиться в куче или в стеке.

Ответы [ 7 ]

36 голосов
/ 13 января 2012
string s = "Hello world";
char* s2 = s.c_str();

Будет ли s2 выделяться в стеке или в куче?Другими словами ... Нужно ли удалять s2?

Нет, не delete s2!

s2 в стекеесли приведенный выше код находится внутри функции;если код находится в глобальной области видимости или области имен, то s2 будет находиться в некотором статически размещенном динамически инициализированном сегменте данных.В любом случае, это указатель на символ (который в данном случае оказывается первым 'H' символом в представлении ASCIIZ текстового содержимого s).Этот текст сам по себе находится там, где объект s хотел создать это представление.Реализации могут делать это так, как им нравится, но решающий выбор реализации для std::string заключается в том, обеспечивает ли она «оптимизацию коротких строк», которая позволяет вставлять очень короткие строки непосредственно в объект s, и может ли "Hello world"достаточно коротка, чтобы извлечь выгоду из этой оптимизации:

  • , если это так, то s2 будет указывать на память внутри s, которая будет распределена в стеке или статически, как объяснено для s2 выше.
  • в противном случае внутри s будет указатель на динамически выделяемую память (free-store / heap), в которой будет отображаться содержимое «Hello world \ 0», адрес которого возвращается .c_str(), и s2 будет копией этого значения указателя.

Обратите внимание, что c_str() равно const, поэтому для компиляции вашего кода вам нужно изменить на const char* s2 = ....

Вы не должны delete s2.Данные, которым s2 баллы по-прежнему принадлежат и управляются объектом s, будут аннулированы любым вызовом не-1043 * методов s или s, выходящими за пределы области.

string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();

Будет ли s2 теперь в куче, поскольку его источник был в куче?

Этот код не компилируется, так как s не является указателем истрока не имеет конструктора типа string(std::string*).Вы можете изменить его на:

string* s = new string("Hello, mr. heap...");

... или ...

string s = *new string("Hello, mr. heap...");

Последний создает утечку памяти и не служит никакой полезной цели, поэтому давайте предположим первый.Тогда:

char* s2 = s.c_str();

... должно стать ...

char* s2 = s->c_str();

Будет ли s2 теперь в куче, так как его источник был в куче?

Да.Во всех сценариях, в частности, если сам по себе s находится в куче, то:

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

Но, опять же, дажезная наверняка, что s2 указывает на выделенную кучу память, вашему коду не нужно освобождать эту память - это будет сделано автоматически при удалении s:

string* s = new string("Hello, mr. heap...");
const char* s2 = s->c_str();
...use s2 for something...
delete s;   // "destruct" s and deallocate the heap used for it...

Конечно, обычно этолучше просто использовать string s("xyz");, если вам не нужен срок службы за пределами локальной области, а std::unique_ptr<std::string> или std::shared_ptr<std::string> в противном случае.

15 голосов
/ 13 января 2012

c_str() возвращает указатель на внутренний буфер в объекте string - вы никогда не free() / delete it.

Он действителен только в том случае, если string, на который он указывает, находится в области видимости. Кроме того, если вы вызываете неконстантный метод объекта string, он больше не гарантируется как действительный.

http://www.cplusplus.com/reference/string/string/c_str/

(отредактировано для ясности на основе комментариев ниже)

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

Во-первых, даже ваша оригинальная строка не выделяется в стеке, как вы, кажется, верите.По крайней мере, не совсем.Если ваш string s объявлен как локальная переменная, только "string объект" сам "размещен в стеке".Управляемая последовательность этого строкового объекта размещается где-то еще.Вы не должны знать, где он расположен, но в большинстве случаев он размещается в куче.Т.е. фактическая строка "Hello world", сохраненная s в вашем первом примере, обычно выделяется в куче, независимо от того, где вы объявляете s.

Во-вторых, около c_str().

В исходной спецификации C ++ (C ++ 98) c_str обычно возвращал указатель на независимый буфер, выделенный где-то.Опять же, вы не должны знать, где он расположен, но в общем случае он должен был быть размещен в куче.Большинство реализаций std::string следили за тем, чтобы их контролируемая последовательность всегда заканчивалась нулем, поэтому их c_str возвращал прямой указатель на контролируемую последовательность.

В новой спецификации C ++ (C ++ 11)теперь требуется, чтобы c_str возвращал прямой указатель на контролируемую последовательность.

Другими словами, в общем случае результат c_str будет указывать на выделенную кучу память даже для локальной std::stringобъекты.Ваш первый пример не отличается от вашего второго примера в этом отношении.Однако в любом случае память, указанная c_str(), не принадлежит вам.Вы не должны освобождать это.Вы даже не должны знать, где он находится.

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

std::string::c_str() возвращает const char*, а не char *.Это довольно хороший признак того, что вам не нужно освобождать его.Память управляется экземпляром (см. Некоторые подробности в этой ссылке , например), поэтому она действительна только тогда, когда действителен экземпляр строки.

2 голосов
/ 13 января 2012

s2 будет действовать до тех пор, пока s остается в области действия. Это указатель на память, которой владеет s. Смотрите, например эта документация MSDN : "строка имеет ограниченное время жизни и принадлежит строке класса."

Если вы хотите использовать std::string внутри функции в качестве фабрики для обработки строк, а затем возвращать строки в стиле c, вы должны выделить кучу памяти для возвращаемого значения. Получите пробел, используя malloc или new, а затем скопируйте содержимое s.c_str().

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

Будет ли s2 выделяться в стеке или в куче?

Может быть в любом. Например, если класс std::string выполняет небольшую оптимизацию строки, данные будут находиться в стеке, если их размер ниже порога SSO, и в противном случае в куче. (И все это при условии, что сам объект std::string находится в стеке.)

Нужно ли удалять s2?

Нет, объект массива символов, возвращаемый c_str, принадлежит строковому объекту.

Будет ли s2 теперь в куче, поскольку его источник был в куче?

В этом случае данные, скорее всего, будут постоянно находиться в куче, даже при выполнении единого входа. Но редко есть причина для динамического выделения объекта std::string.

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

Это зависит.Если я правильно помню, CString делает копию входной строки, так что нет, вам не нужно иметь никаких специальных подпрограмм выделения кучи.

...