Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22

resize or reserve

07.07.2020, 11:07. Показов 3079. Ответов 39
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Мое почтение, джентльмены.
Нужно быстро выделить буфер для работы с адресной арифметикой.
И так, чтобы без ручного освобождения памяти.
Был предложен след подход:
C++
1
2
3
4
const DWORD  nNumberOfBytesToRead = 16777216;
std::string s;
s.resize( nNumberOfBytesToRead + 4096 * 2);
char* buf = &s[4096 - size_t(s.c_str()) % 4096]; //выравнивание
Не нравится, то что resize() - это трата времени на заполнение строки.

Вопрос знатокам:
C++
1
2
3
4
const DWORD  nNumberOfBytesToRead = 16777216;
std::string s;
s.reserve( nNumberOfBytesToRead + 4096 * 2);
char* buf = &s[4096 - size_t(s.c_str()) % 4096]; //выравнивание
Будет ли этот код UB и почему?
Компилятор (VS2017) в режиме отладки ругается (обращение к не инициализированной строке), в релиз - все норм.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.07.2020, 11:07
Ответы с готовыми решениями:

Разница между resize и reserve
Всем доброе утро! Следующий вопрос не дает мне спать по ночам - в чём таки разница между resize и reserve класса vector?.. Думала, что...

QVector::reserve() + std::vector::reserve() и добавление в начало
Если зарезервировать в новосозданном векторе место, а затем добавлять объекты классов в начало - будет ли эффективнее вставка? Или...

Теория. Почему в данном случае copy() не работает после reserve(), но работает после resize()?
Есть такая функция: void Array::SetStartIndexes(sz3_Arr_t *array) { start_index.reserve(array->size()); ...

39
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.07.2020, 11:18
Лучший ответ Сообщение было отмечено bedvit как решение

Решение

Цитата Сообщение от bedvit Посмотреть сообщение
Будет ли этот код UB и почему?
Компилятор (VS2017) в режиме отладки ругается (обращение к не инициализированной строке), в релиз - все норм.
Потому что не надо использовать std::string в качестве буфера (и std::vector тоже)
Сделай
C++
1
2
3
const DWORD  nNumberOfBytesToRead = 16777216;
std::unique_ptr<char[]> sp(new char[nNumberOfBytesToRead + 4096]);
char* buf = sp.get() + nNumberOfBytesToRead % 4096; //выравнивание
1
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 12:02  [ТС]
oleg-m1973, спасибо.
Ранее делал так
C++
1
2
3
const DWORD  nNumberOfBytesToRead = 16777216;   
std::unique_ptr<char[]> bufPtr = std::make_unique<char[]>(nNumberOfBytesToRead + 4096);
char* buf = bufPtr.release() + 4096 - (size_t(bufPtr.get()) % 4096);
с учетом вашей инфо:
C++
1
2
3
const DWORD  nNumberOfBytesToRead = 16777216;
std::unique_ptr<char[]> bufPtr(new char[nNumberOfBytesToRead + 4096]);
char* buf = bufPtr.get() + 4096 - (size_t(bufPtr.get()) % 4096);
работает быстрее (хотя советуют std::make_unique) и исправляет мою ошибку с release() - returns a pointer to the managed object and releases the ownership, из-за чего был неработоспособен вариант.

Добавлено через 6 минут
Цитата Сообщение от bedvit Посмотреть сообщение
Будет ли этот код UB и почему?
Все же интересен ответ.
Хотя рабочий вариант через std::unique_ptr представляется целесообразным и думаю использовать его.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
07.07.2020, 12:08
Цитата Сообщение от bedvit Посмотреть сообщение
Все же интересен ответ.
UB будет.
Потому что нарушаются установленные стандартом условия для доступа к элементам std::string.

Доступ возможен в пределах [0..size()], а вы рассчитываете на [0..capacity()]

Тут все написано: https://eel.is/c++draft/basic.string
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.07.2020, 12:13
Цитата Сообщение от bedvit Посмотреть сообщение
Все же интересен ответ.
Хотя рабочий вариант через std::unique_ptr представляется целесообразным и думаю использовать его.
В случае с reserve, ты сделаешь из std::string тот же самый unique_ptr<char[]>, только с кучей методов, которые работать не будут. Можешь назвать это UB.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 12:19  [ТС]
DrOffset, а мне не нужен доступ к к элементам std::string. Мне нужен просто кусок памяти, который потом автоматом освободится. А работать я буду через указатели char*, и функционал типовой std::string тоже не нужен.
Правильно ли я понимаю, при reserve() непрерывный кусок памяти выделен, и при выход за границы видимости, должен быть освобожден.

Добавлено через 2 минуты
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
только с кучей методов, которые работать не будут
они и не нужны, все же работать так будет, в чем UB?
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
тот же самый unique_ptr<char[]>
здесь согласен, выше написал, что включу в рабочий вариант вместо std::string.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.07.2020, 12:24
Цитата Сообщение от bedvit Посмотреть сообщение
они и не нужны, все же работать так будет, в чем UB?
То что ты думаешь, что они "не нужны", не значит что ты ими однажды не воспользуешься. Не стоит закладываться на свою супер-внимательность. Лучше сразу не привыкать к плохому.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 12:36  [ТС]
Согласен.
Итого, как я понял:
1. UB нет, но часть функционала std::string не работает (нужен он или нет, плохо ли это или нет - вопрос другой).
2. С учётом, что есть std::unique_ptr, первый вариант - это ненужные костыли.

Всем спасибо.

P.S.
Судя по времени (сравнимого с std::string.resize()) std::make_unique тоже заполняет строку.
0
фрилансер
 Аватар для Алексей1153
6466 / 5682 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
07.07.2020, 12:53
bedvit, если функционал std::string таки не нужен, сделай свой класс-вроппер, внутри которого будет malloc в конструкторе и free в деструкторе

Добавлено через 3 минуты
или, если это возможно, используй глобальную или статическую переменную std::string с выделенным буфером (тогда и перевыделять не придётся). Но нужно учитывать многопоточность, если присутствует
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
07.07.2020, 13:01
Цитата Сообщение от bedvit Посмотреть сообщение
Судя по времени (сравнимого с std::string.resize()) std::make_unique тоже заполняет строку.
А может быть и там и там возвращается сразу участок с нулями, и resize ничего не заполняет?

Цитата Сообщение от bedvit Посмотреть сообщение
а мне не нужен доступ к к элементам std::string. Мне нужен просто кусок памяти, который потом автоматом освободится. А работать я буду через указатели char*, и функционал типовой std::string тоже не нужен.
Не важно как ты потом будешь получать доступ к элементам. По ссылке же есть всё.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
07.07.2020, 13:09
Цитата Сообщение от bedvit Посмотреть сообщение
а мне не нужен доступ к к элементам std::string. Мне нужен просто кусок памяти, который потом автоматом освободится.
std::string не предоставляет доступ к "куску памяти", он предоставляет доступ к элементам.
Поэтому как только кусок памяти перестает физически совпадать с валидными элементами в рамках контракта класса,то вы получаете UB.

Добавлено через 1 минуту
Цитата Сообщение от bedvit Посмотреть сообщение
UB нет,
Конечно есть.
Вы похоже просто не понимаете что такое UB.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 14:11  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
возвращается сразу участок с нулями
если там ранее были нули, то возможно. Но кто знает, что в новом участке памяти может быть, нужно что-бы что-то проставило туда эти нули. А это время.
Алексей1153, думал об этом, но std::unique_ptr выглядит вполне неплохо.
Цитата Сообщение от DrOffset Посмотреть сообщение
Поэтому как только кусок памяти перестает физически совпадать с валидными элементами в рамках контракта класса,то вы получаете UB.
Сможете привести небольшой пример?
Такой код отрабатывает (внешне) нормально:
C++
1
2
3
4
5
6
7
8
9
10
11
12
    std::string s;
    s.reserve( nNumberOfBytesToRead + 4096 );//resize//reserve
    std::cout << size_t(s.c_str()) << std::endl;
    char* buf = &s[4096 - size_t(s.c_str()) % 4096]; //выравнивание
    std::cout << size_t(buf) << std::endl;
    char* buf2 = buf + 1;
    std::cout << size_t(buf2) << std::endl;
    buf2[0]= 'e';
    buf2[1] = 'n';
    buf2[2] = 'd';
    buf2[3] = '\0';
    std::cout << buf2 << std::endl;
Миниатюры
resize or reserve  
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
07.07.2020, 14:12
Цитата Сообщение от bedvit Посмотреть сообщение
Такой код отрабатывает (внешне) нормально
Здесь нет никакого противоречия. Нормальное "отрабатывание" - это вариант UB.
0
фрилансер
 Аватар для Алексей1153
6466 / 5682 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
07.07.2020, 14:40
bedvit, к reserve можно относиться как к "настоятельной рекомендации заранее выделить память". То есть, в 99.9999% это сразу и произойдёт, но если использовать память не через функции класса, то когда-нибудь код свалится в самый радужный момент

Цитата Сообщение от bedvit Посмотреть сообщение
std::unique_ptr выглядит вполне неплохо
это и есть вроппер, только он тут ни при чём, потому что память для него выделяешь через new
Цитата Сообщение от bedvit Посмотреть сообщение
std::unique_ptr<char[]> bufPtr(new char[nNumberOfBytesToRead + 4096]);
, который может обнулять выделенный блок. А вот память, выделенную malloc в std::unique_ptr совать нельзя. Остаётся выход - свой вроппер. Тем более, это не сложно
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
07.07.2020, 15:32
Ассоциация UB обязательно c "падением" программы это вредная и некорректная ассоциация.
UB - это всего лишь отсутствие описанного поведения. Пока мы работаем в рамках описанного поведения, то программа ведет себя предсказуемо и переносимо - это гарантируется описанием. Если мы начинаем делать те вещи, которые вообще не описаны, или явно помечены как имеющие произвольное поведение, то мы теряем гарантии предсказуемой работы и переносимости. Естественно, потеря гарантии еще не означает обязательную поломку.

Еще более на пальцах.
Кликните здесь для просмотра всего текста
Вы купили телевизор, на нем написано "Не включать при влажности больше 95%". Что будет, если включить - неизвестно, в документации ничего про это не написано. Это и есть UB. Дальше вы топите баню на максимум, несете туда телевизор и включаете. Бам - работает. Ничего не произошло. По крайней мере пока. Выключили телевизор, и заявляете:
Цитата Сообщение от bedvit Посмотреть сообщение
отрабатывает (внешне) нормально
Теперь представим, что телевизор щелкнул и погас - сломался. Но в документации было написано - "не включать". А вы включили. Значит сервиса вам не видать.
Что это значит для вас, как для пользователя? Это значит, что вы не можете в полной уверенности советовать другим ставить этот телевизор в баню. Если что - виноваты вы. Вы можете пользоваться им в том же режиме и надеяться, что все и дальше будет нормально. Но опять же, если что - виноваты вы. И все вышесказанное нисколько не означает, что не может быть такой ситуации, когда телевизор проработал в бане 30 лет, пока ее решили не снести.
Какие примеры можно привести тут, чтобы доказать, что здесь UB? Да никаких. У вас может вообще не быть примеров отрицательного поведения. Но это ничего не меняет. Единственным и полным доказательством наличия UB является явное указание этого в документации или отсутствие в ней упоминаний о поведении в рассматриваемом случае.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 15:59  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
через new
Цитата Сообщение от Алексей1153 Посмотреть сообщение
выделенную malloc в std::unique_ptr совать нельзя
Использовать realloc в данном случае не предвидится, в чем преимущество malloc над new?
Цитата Сообщение от DrOffset Посмотреть сообщение
Еще более на пальцах.
Ну вот теперь все прояснилось
0
фрилансер
 Аватар для Алексей1153
6466 / 5682 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
07.07.2020, 16:08
bedvit,

так ведь - https://www.cyberforum.ru/post14071034.html

и там же https://www.cyberforum.ru/post14071337.html
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
07.07.2020, 16:36
Цитата Сообщение от bedvit Посмотреть сообщение
Но кто знает, что в новом участке памяти может быть
Реализация может запросить сразу зануленый участок.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,140
Записей в блоге: 22
07.07.2020, 16:48  [ТС]
Алексей1153, ну так это malloc и calloc. Под капотом new. разве не malloc. пишут что разница небольшая.

Протестировал
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    int N = 1000000;
    auto start = std::chrono::steady_clock::now();
    for (int i = 0; i < N; i++) {
        char* p = (char*)malloc(1024);
        free(p);
    }
    auto end = std::chrono::steady_clock::now();
 
    std::cout << "malloc + free: " << (end - start).count() << std::endl;
 
    start = std::chrono::steady_clock::now();
    for (int i = 0; i < N; i++) {
        char* p = new char[1024];
        delete[] p;
    }
    end = std::chrono::steady_clock::now();
 
    std::cout << "new[] + delete[]: " << (end - start).count() << std::endl;
malloc + free: 35813903
new[] + delete[]: 36178941
Добавлено через 1 минуту
Цитата Сообщение от Croessmah Посмотреть сообщение
Реализация может запросить сразу зануленый участок.
А что его занулит?
0
фрилансер
 Аватар для Алексей1153
6466 / 5682 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
07.07.2020, 16:51
bedvit, даже так... Ну, я не знаю тогда, в чём тут фокус
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.07.2020, 16:51
Помогаю со студенческими работами здесь

Vector reserve
Если использовать reserve с push_back это будет экономия ресурсов и производительности? vector&lt;int&gt;arr; arr.reserve(10); ...

How can I resize all controls or just resize the space between them?
Hi. How can I resize all controls or just resize the space between them, when the form is resized in the runtime? Thanx in advance

Двумерный вектор. Не работает reserve()
Пишу динамическую таблицу, элементы и размеры которой задаются из .txt. Использую двумерный вектор. Но не получается сделать reserve() -...

Реализация функций reserve и clear для вектора
Мне нужно самой написать реализацию. От что у меня есть: template&lt;typename T&gt; void Vector&lt;T&gt;::PopBack() { mVector.~T(); ...

Обмен валют Яндекс-деньги и Liberty Reserve
кто попался на эту лажу обмен валют Яндекс-деньги и Liberty Reserve? кому не пришли деньги


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Вывод данных через динамический список в справочнике
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Функция заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
10 пpимет, которые всегда сбываются
Maks 31.03.2026
1. Чтобы, наконец, пришла маршрутка, надо закурить. Если сигарета последняя, маршрутка придет еще до второй затяжки даже вопреки расписанию. 2. Нaдоели зима и снег? Не надо переезжать. Достаточно. . .
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 31.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru