Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
0 / 0 / 0
Регистрация: 21.08.2024
Сообщений: 24

Динамическое выделение памяти new/delete

26.08.2024, 23:49. Показов 2640. Ответов 28

Студворк — интернет-сервис помощи студентам
Всем здравствуйте. Читаю книгу Стивена Прата и наткнулся на такую ситуацию:
В книге описан подобный приведенному ниже пример (в нём использую свой связный список):
C++
1
2
3
4
5
6
7
8
9
char* buf = new char[512];
List* pl1, * pl2;
pl1 = new (buf) List();
pl1->push_back("string");
pl1->print_list();
pl2 = new (buf) List();
pl2->push_back("line");
pl1->print_list();
delete[] buf;
Так вот в книге написано, что при вызове delete [] buf; удаляется весь блок памяти *char buf, но деструкторы для объектов класса, созданных в блоке операцией new с размещением, не вызываются. При этом если я пытаюсь обратится к pl1 или pl2, выводится белиберда, что говорит о том, что данные то удалены. Я, видимо, чего-то не понимаю: если данные расположены в buf, то, очистив этот buf, мы очистим и сами данные.
Объясните, пожалуйста, что и где я написал не так или понял не так.

Добавлено через 15 минут
Забыл добавить, что для pl2 при выделении места в buf в книге добавляется N-ное количество байт (sizeof(List)) относительно размещения pl1.
т.е. по книжному код выглядит так:
C++
1
2
3
4
5
6
7
8
9
10
11
 char* buf = new char[512];
 List* pl1, * pl2;
 pl1 = new (buf) List();
 pl1->push_back("string");
 pl1->print_list();
 pl2 = new (buf+214) List();
 pl2->push_back("line");
 pl1->print_list();
pl1->~List(); // ??
pl2->~List(); // ?? на следующей строчке удаление всего буфера 
 delete[] buf;
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.08.2024, 23:49
Ответы с готовыми решениями:

Динамическое выделение памяти под массив структур (new/delete)
Люди добрые, подскажите пожалуйста, где в моем коде закралась ошибка? Интернет перечитал, во всех примерах код, подобный моему работает, а...

почему не delete (выделение памяти)
почему в примерах в мсдне не высвобождается память после использования asctime, ctime? #include <time.h> #include <stdio.h>...

Распределение памяти. Динамическое выделение памяти
an-1 an-2 ... a2

28
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
27.08.2024, 16:37
Студворк — интернет-сервис помощи студентам
Встречал в embeded, когда объект надо расположить строго по определённому адресу (на память не вспомню, но есть синтаксис, позволяющий указать адрес куда сделать new).
Обычно такой "объект" по сути представляет из себя "именованные" конкретные адреса в памяти, связанные с какой-то аппаратурой, плюс удобные методы-обертки.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
27.08.2024, 16:46
Цитата Сообщение от Royal_X Посмотреть сообщение
Но чёт на практике я не вижу этот placement new...
Ну ты спрашивал когда есть смысл использовать, я на это дал свой ответ Вот тебе даже пример накатал (далее дам более практическую теорию):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <chrono>
#include <cstdlib>
#include <iostream>
 
struct Test
{
    int m_value;
    Test()
    {
        m_value = rand() % 2;
    }
};
 
int main()
{
    char buf[sizeof(Test)];
    
    auto start = std::chrono::high_resolution_clock::now();
    unsigned int result = 0;
    for (int i = 0; i < 100000; i++)
    {
        //Test* t = new(buf) Test;
        Test* t = new Test;
        result += t->m_value;
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
 
    std::cout << "time: " << duration << std::endl;
}
В цикле есть два способа создать объект. Один с placement new, другой без. Проверь оба и сообщи о разнице. Если компьютер мощный и разница не особо заметна, то попробуй увеличить количество итераций. Суммарно (считай в пределе, при количестве итераций стремящихся к бесконечности) ты получишь прирост в производительности.

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

И еще когда используется placement new, нужно помнить об alignment requirements. Если ты вдруг разместишь объект по адресу, по которому он не имеет право существовать, то получишь UB или потерю производительности из-за обращения к данным по невыровненному адресу.
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6325 / 3053 / 1054
Регистрация: 01.06.2021
Сообщений: 11,671
27.08.2024, 17:01
Undisputed, ещё давно разрабы gcc обсуждали про атаку переполнением буфера для placement new: https://gcc.gnu.org/legacy-ml/... 02001.html
Им даже пришлось выпустить патч. Вот и я подумал, не из-за того, что placement new это источник уязвимостей в коде, его многие избегают?
Конечно, теоретические примеры, в котором placement new имеет преимущества, это одно. Но на практике совсем другое.
Вот, KSergey9 заговорил об embedded и тут есть логика в оправданности его применения. С кастомными аллокаторами тоже есть кое-какая логика. Но все равно, я не вижу, чтобы его массово применяли.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,350
27.08.2024, 17:08
Цитата Сообщение от Royal_X Посмотреть сообщение
а когда есть смысл использовать placement new? В каких случаях это оправдано? Я ещё давно о нем читал, но на практике не встречал.
Тут сотни разных примеров можно привести....

Всякий раз, например, когда вам нужно разделить выделение памяти и конструирование объектов, понадобится placement new. Возьмите, например, std::vector, в котором есть такое разделение, т.е. есть capacity и есть size - количество выделенной "сырой" памяти и количество уже сконструированных объектов. Понятно, что std::vector будет вынужден отдельно выделять память и отдельно конструировать в ней объекты. Последнее делается через placement new.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
27.08.2024, 17:09
Цитата Сообщение от Royal_X Посмотреть сообщение
Конечно, теоретические примеры, в котором placement new имеет преимущества, это одно. Но на практике совсем другое.
Как совсем другое? Всё то же самое, если использовать правильно. Если получается переполнение буфера, значит это ошибка программиста, а не placement new плохой.

Даже многие стандартные контейнеры в С++ умеют выделять память для своих элементов через кастомный аллокатор. Это как бы намекает, что именно placement new они и используют для размещения объектов в памяти, которую получают через шаблонный параметр для аллокатора.

Добавлено через 32 секунды
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Возьмите, например, std::vector, в котором есть такое разделение
Вот-вот... об этом я и говорю
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,350
27.08.2024, 17:10
Цитата Сообщение от Royal_X Посмотреть сообщение
Но все равно, я не вижу, чтобы его массово применяли.
Вы это не видите, потому что его массовое применение "заооболочено" в конструкции более высокого уровня. Либо это тонкая оболочка вроде std::construct_at, либо более толстая, вроде std::optional или std::variant.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
27.08.2024, 17:40
Выше в моем сообщении #22 есть ошибка, хотя она может и не проявлять себя. Буфер должен быть выровнен должным образом, что бы туда можно было положить объект типа Test через placement new.

Сделать это можно создав буфер так:
C++
1
alignas (Test) char buf[sizeof(Test)];
либо для выделения памяти использовать std::aligned_storage
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,350
28.08.2024, 02:25
Цитата Сообщение от Royal_X Посмотреть сообщение
а когда есть смысл использовать placement new?
(В продолжение...) Классическая ситуация, которая время от времени возникает и в вопросах здесь: выбор типа и/или способа и/или момента конструкции локального объекта в run-time. А именно, ситуации когда

1. В зависимости от условия нам нужен один объект либо типа A, либо типа B (типы могут быть полиморфными наследниками одной базы, а могут быть не связаны вообще).
2. Нам нужен объект типа A, но в зависимости от условия конструировать его нужно одним или другим конструктором.
3. Нам как бы нужен объект типа A, но в зависимости от условия он может быть не нужен вообще

Как поступать в таких ситуациях? В книжках для начинающих в таких случаях обычно советуют создавать объекты динамически при помощи new. Например, для решения проблемы номер 3 предлагается делать что-то такое

C++
1
2
3
4
5
6
7
8
9
{
  A *p = nullptr;
  if (условие)
    p = new A(1, 2, 3);
 
  ...
 
  delete p;
}
Но и ежу понятно, что в таком коде нет никаких причин использовать динамическую память (если тип не является гигантским). Динамическая память в таком примере - это накладной расход, который в этом случае навязывается чисто паразитным образом. Можнo ли обойтись без динамической памяти? Вот тут-то и приходит на помощь placement new

C++
1
2
3
4
5
6
7
8
9
10
11
{
  alignas(A) char buffer[sizeof(A)];
  A *p = nullptr;
  if (условие)
    p = new(buffer) A(1, 2, 3);
 
  ...
 
  if (p)
    p->~A();
}
Но в современном С++ все это уже завернуто для вас в std::optional: Вызов нужного конструктора (пример по ссылке и для проблемы 2)
2
 Аватар для Наталья8
629 / 387 / 67
Регистрация: 09.03.2016
Сообщений: 4,311
28.08.2024, 02:40
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//==================== Вторая часть. Собственно переименовывает.
 
 char *From = nullptr, *To = nullptr;
 bool one(true);// Один раз создать массивы.
 SHFILEOPSTRUCTA op;
 short store_number(0);
 do {
     short number(store_number); // ============  
*(strrchr(buffer, 'p')+1) = '\0';// Для входа в верхний цикл (на хвосте old_clip)
     while (_access(buffer, 0) == 0)// Поиск дыры (1234 789...  папки есть)
    sprintf(strrchr(buffer, '\\') + 9, "%d", ++number);//number для нового порядка
 store_number = number;
     //====================
 if (number == counter) {
     if (From && To) { delete[] From; delete[] To;
     From = nullptr; To = nullptr;
     }
  return;//Здесь вылетит если в каталоге порядок (отработает только верхний цикл) 
     }
     if (one) {// Создать массив на куче в случае непорядка в каталоге и почистить память (выше)
         To = new char[strlen(buffer) + 5];// To <<--- Папка назначения
         From = new char[strlen(buffer) + 5];// Один раз массив.
         one = false;
     }
     strcpy(To, buffer); To[strlen(buffer) + 1] = '\0';
     //====================
while (_access(buffer, 0) != 0)// Нахождение последнего номера папки в промежутке
             sprintf(strrchr(buffer, '\\') + 9, "%d", ++number);// для переименования его в порядковый
     strcpy(From, buffer); From[strlen(buffer) + 1] = '\0';
     //====================      
     ZeroMemory(&op, sizeof(op));
     op.wFunc = FO_RENAME;//  FO_MOVE // FO_DELETE // FO_RENAME
     op.pFrom = From;
     op.pTo = To;
     op.fFlags = FOF_RENAMEONCOLLISION | FOF_SIMPLEPROGRESS;//FOF_NOERRORUI;
 } while (SHFileOperationA(&op) == 0);
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.08.2024, 02:40

Динамическое выделение памяти
Использовать динамическое выделение памяти для программы : #include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;iomanip&gt; ...

Динамическое выделение памяти
Дан вещественный массив А, все элементы которого различны. В каждой строке найти элемент с наименьшим значением, а затем среди найденных...

Динамическое выделение памяти
Создайте динамический массив, хранящий в первой строке имя, а во второй - телефон. Организуйте поиск по имени и по номеру телефона и...

Динамическое выделение памяти new
Доброго времени всем :) Недавно начал вникать в прелести c++, однако встретился с неприступной холодностью его и непониманием моих...

Динамическое выделение памяти
Имеется: #define Index 1000 typedef int BaseType; typedef BaseType TMemList; typedef unsigned ptrel; typedef struct List...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
29
Ответ Создать тему
Новые блоги и статьи
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru