Подтвердить что ты не робот

Требуется ли удаление str.c_str()?

Мой код несколько раз преобразует строки С++ в 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 в куче, я знаю, что указатель находится в стеке. Я спрашиваю, будет ли то, что он указывает, на кучу или стек.

4b9b3361

Ответ 1

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

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

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

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

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

Вам не нужно удалять s2, no. Данные, к которым точки s2 все еще принадлежат и управляются объектом s, будут признаны недействительными любым вызовом методов const 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> в противном случае.

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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

Мне нужно удалить s2?

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

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

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

Ответ 7

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