Как управляется память C ++, когда строковое значение назначается, а затем изменяется путем присвоения другого значения? - PullRequest
0 голосов
/ 06 февраля 2020

Мне действительно нужно понять, как память управляется в C ++ для следующих случаев:

Case-1:

string s1 = "ABCD";
s1= "EFGH";

Что происходит в памяти со строкой значение "ABCD"? Это автоматически освобождается? Или здесь утечка памяти?

Случай 2:

char* val = "ABCD";
val = "EFGH";

Как и в случае 1, чем отличается случай 2 от случая 1?

Case-3:

string s1 = "ABCD";
string s2 = s1;

Выделена ли отдельная память для s2 со значением "ABCD"? Или s1 и s2 указывают на одну и ту же область памяти здесь? Как управляется память в этом случае?

Пожалуйста, поделитесь ссылкой, чтобы изучить их глубже? Любые предложения определенно помогут мне.

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Case 1

string s1 = "ABCD";

string обрабатывает выделение памяти для хранения "ABCD" для вас. Деструктор string будет вызван автоматически, когда s1 выйдет из области видимости, что освободит память, выделенную string.

s1 = "EFGH";

Оператор назначения копирования string перезапишет сохранение памяти "ABCD" с "EFGH".

Случай 2

char* val = "ABCD";
val = "EFGH";

Фред Ларсон ответил на этот вопрос в комментариях выше, вы просто переназначаете указатель на строку stati c. Стек будет выделять память только для указателя (не для данных), и указатель будет автоматически освобожден, когда val выйдет из области видимости.

Случай 3

string s1 = "ABCD";
string s2 = s1;

s2 выделит память и скопирует s1. Реализация копирования при записи оператора присваивания копии будет выделять и копировать память только в случае мутации s2. Однако начиная с C ++ 11 кажется, что реализации COW std::string больше не разрешены ( Легальность реализации COW std :: string в C ++ 11 ).

Case 4

Вот пример сценария, когда вам делать нужно беспокоиться об освобождении выделенной памяти.

Вы можете использовать это, если вам нужно string, чтобы пережить область, в которой он был создан. (На практике обычно следует избегать такого подхода. См. Случай 5 ниже.)

string* s1 = new string("ABCD");
delete s1;

В этом примере string все еще внутренне управляет памятью для хранения "ABCD", но указатель string выделен в куче, а деструктор string не будет вызван, когда s1 выйдет из области видимости. В этом случае вы несете ответственность за использование delete для обеспечения очистки памяти, когда s1 больше не требуется.

Случай 5

shared_ptr<string> s1 = make_shared<string>("EFGH");

shared_ptr обычно путь к go против new и delete. Общие указатели предотвращают много утечек памяти из-за ошибок программирования. shared_ptr обрабатывает delete для вас и использует подсчет ссылок, чтобы поддерживать string до тех пор, пока не будет уничтожена последняя ссылка.

1 голос
/ 06 февраля 2020
  1. Современные std::string реализации примерно следуют этим правилам (хорошо объяснено здесь тоже):

    • Короткие строки (<= 26 символов?) размещается в стеке с помощью оптимизации под названием SSO. </li>
    • Строки длиннее, чем они выделяются в куче. Реализация std :: string внутренне управляет как выделением, так и освобождением.
  2. const char* x = "ABCD" выделяется в стеке в хранилище c и указатель на него хранится в стеке. Это можно увидеть в ссылке CE здесь , где rsp:rsp-8 указывает на .LC0.

Учитывая приведенные выше наблюдения:

  • Случай 1: размещение x в стеке, а затем копирование нового значения "EFGH" в s1 без выделения дополнительного места в стеке. CE Link
  • Случай 2: val указывает на хранилище stati c, где хранится «ABCD», а затем на «EFGH». CE Link
  • Случай 3: Это будет (без включенной оптимизации) выделять 2 std :: strings в стеке ( CE Link ), как в случае 1.

Как отмечено в комментариях, возможны альтернативные реализации std::string, например (1) Те, которые не реализуют SSO (2) Реализация копирования при записи.

...