По факту, на юникс-подобных системах обычно можно рассчитывать что new это простая обертка для malloc, и работать будет. Но в общем случае это конечно UB
Да мне и не нужны конструкторы во время инициализации новой (дополненной realloc) памяти. Просто потом будут вызываться конструкторы копирования на эту память.
теоретически - можно. даже где-то попадалась статья какого-то программиста, который вместо new выделял память под класс и вызывал конструктор и это работало. но естественно, что класс может иметь нетривиальный конструктор и тогда надо учитывать все нюансы. опять же, зачем классу realloc? класс сам по себе и его хранимые данные часто не одна и та же непрерывная область памяти. поэтому вообразить себе ситуацию, что объекту понадобится именно реаллок, довольно трудно. опять же, у каждого компилятора свои способы хранения класса и его данных.
В смысле в изменение размера? Может он. Точнее для этого он и делался.
Вроде как он выделяет новый кусок памяти и копирует туда. А у realloc() фишка в том, что у него достаточно часто увеличение размера памяти происходит без изменения стартового адреса. И соответственно, без необходимости копировать.
==23133==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs free) on 0x60200000eff0
#0 0x7f93be1d3961 in realloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98961)
#1 0x400910 in main (/home/fsb4000/github/1/a.out+0x400910)
#2 0x7f93bd06b82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400818 in _start (/home/fsb4000/github/1/a.out+0x400818)
0x60200000eff0 is located 0 bytes inside of 8-byte region [0x60200000eff0,0x60200000eff8)
allocated by thread T0 here:
#0 0x7f93be1d46b2 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x996b2)
#1 0x4008f8 in main (/home/fsb4000/github/1/a.out+0x4008f8)
#2 0x7f93bd06b82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: alloc-dealloc-mismatch ??:0 realloc
Если изменить код так
#include <cstdlib>
int main()
{
int* g = new int[2];
int* g1 = (int*)realloc(g, sizeof(int) * 3);
g1[2] = 0;
//delete[]g1;
free(g1);
}
То получаем тоже самое
=================================================================
==23227==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs free) on 0x60200000eff0
#0 0x7fec48533961 in realloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98961)
#1 0x400910 in main (/home/fsb4000/github/1/a.out+0x400910)
#2 0x7fec473cb82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400818 in _start (/home/fsb4000/github/1/a.out+0x400818)
0x60200000eff0 is located 0 bytes inside of 8-byte region [0x60200000eff0,0x60200000eff8)
allocated by thread T0 here:
#0 0x7fec485346b2 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x996b2)
#1 0x4008f8 in main (/home/fsb4000/github/1/a.out+0x4008f8)
#2 0x7fec473cb82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: alloc-dealloc-mismatch ??:0 realloc
В общем случае нельзя, потому что у тебя нет гарантии, что new вернёт тебе реальный адрес выделенной памяти, а не смещённый на сколько-то байт, которые он зарезервировал для служебной информации.
Я немного не то имел в виду. Realloc внутри знает, есть ли за выделенным блоком свободное место. Оно не резервируется сразу, и может быть отдано при другом вызове malloc. Но если к моменту вызова realloc за указанным куском памяти есть достаточного размера свободное место, то аллокатору нет необходимости копировать память в другое место.
Это может дать какие-то проценты скорости; за ними и гонятся.
Зависит от цели. Я конкретно имел ввиду, что placement new может использовать какой-угодно участок памяти. А определение ::operator new для своих целей (аллокаторов) — отдельная история.
realloc работает с памятью, выделенной через malloc. new выделяет память каким угодно способом, совсем не обязательно напрямую через malloc. Поэтому в общем случае нельзя. В частном случае может и будет работать, но это уже особенности реализации new на конкретном компиляторе в конкретном окружении.
Но если для всех тех сущностей, для которых нужен realloc(), ты можешь использовать свой allocator, то напиши свой аллокатор, который точно совместим с realloc() и используй только его.
Разве? Пусть страница памяти занята полностью или частично, она же уже не может быть отдана другому процессу вплоть до освобождения. Тем самым, разница с вектором в значительной мере нивелируется.
А это тут причём? Память не по одной странице у системы запрашивается. По крайней мере, в glibc.
Допустим, у тебя была свободная память:
...........................................
Ты запросил блок вызовом malloc:
XXXXXXX....................................
Потом захотел поменять размер, позвал realloc:
XXXXXXXXXXXXXXX............................
Если то же делать без использования realloc, а с помощью комбинации malloc и free, будет:
XXXXXXXYYYYYYYYYYYYYYY.....................
.......YYYYYYYYYYYYYYY.....................
Понятное дело, что если за XXXXXXX нет свободного места, то будет выделение в новом месте и копирование. Но если есть, копирования можно избежать.
Другой момент — уменьшение размера выделенной памяти тем же realloc. Тут точно перемещать не нужно. Но как бонус аллокатор имеет возможность переиспользовать освободившуюся память для новых вызовов malloc. Без realloc для уменьшения выделенной памяти нужно будет копировать. Ну или всегда держать память выделенной, даже если она стала не нужна.