LINUX.ORG.RU

По факту, на юникс-подобных системах обычно можно рассчитывать что new это простая обертка для malloc, и работать будет. Но в общем случае это конечно UB

annulen ★★★★★ ()
Ответ на: комментарий от annulen

Да даже, если new - это обёртка для malloc, есть ещё конструкторы объектов и если они нетривиальные, то realloc недостаточно.

Begemoth ★★★★★ ()
Ответ на: комментарий от Begemoth

Ну тут уже все в руках ССЗБ. Даже если конструктор нетривиальный, это еще не значит что объект нельзя тривиально перемещать в памяти

annulen ★★★★★ ()
Ответ на: комментарий от Begemoth

Да мне и не нужны конструкторы во время инициализации новой (дополненной realloc) памяти. Просто потом будут вызываться конструкторы копирования на эту память.

normann ★★ ()

теоретически - можно. даже где-то попадалась статья какого-то программиста, который вместо new выделял память под класс и вызывал конструктор и это работало. но естественно, что класс может иметь нетривиальный конструктор и тогда надо учитывать все нюансы. опять же, зачем классу realloc? класс сам по себе и его хранимые данные часто не одна и та же непрерывная область памяти. поэтому вообразить себе ситуацию, что объекту понадобится именно реаллок, довольно трудно. опять же, у каждого компилятора свои способы хранения класса и его данных.

Iron_Bug ★★★★★ ()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

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

Placement new это не что-то экзотическое. Достаточно часто встречается.

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

это не placement new. там чувак именно дёргал конструктор, через вызов по смещению. и это была копиляторозависимая фигня.

Iron_Bug ★★★★★ ()

Лучше не надо, но встречал тех, кто так делает, и что странно, это даже иногда работает

dave ★★★★★ ()
Ответ на: комментарий от Iron_Bug

вообразить себе ситуацию

Выделить память под вектор (член класса) элементы которого объекты класса, а потом увеличить его размер (если понадобится).

normann ★★ ()
Ответ на: комментарий от Begemoth

В смысле в изменение размера? Может он. Точнее для этого он и делался.

Вроде как он выделяет новый кусок памяти и копирует туда. А у realloc() фишка в том, что у него достаточно часто увеличение размера памяти происходит без изменения стартового адреса. И соответственно, без необходимости копировать.

i-rinat ★★★★★ ()

А вот другой вопрос. Допустим я сделал new, потом realloc, и всё это оказалось легальным. Можно ли потом на этом куске памяти использовать delete[]?

normann ★★ ()

Нет, в общем случае - нельзя. Как уже написали - это сработает в тех редких случаях когда new() тупой враппер вокруг malloc().

cvv ★★★★★ ()

можно ли вызывать realloc() для памяти выделенной посредством new в Си++?

Нет.

#include <cstdlib>

int main()
{
    int* g = new int[2];
    int* g1 = (int*)realloc(g, sizeof(int) * 3);
    g1[2] = 0;
    delete[]g1;
}
g++  -fsanitize=address -fsanitize=undefined -fsanitize=leak 1.cpp
==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

fsb4000 ★★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)

Можно, но не нужно.

anonymous ()
Ответ на: комментарий от Iron_Bug

который вместо new выделял память под класс и вызывал конструктор

Это делается тривиально через placement new:

void *place = malloc(sizeof(Class));
Class *cls = new (place) Class{params};

// ...

cls->~Class();
free(place);

https://wandbox.org/permlink/Yz97ScSOC2Lg0Ca1

KennyMinigun ★★★★★ ()
Ответ на: комментарий от normann

А вот другой вопрос. Допустим я сделал new, потом realloc, и всё это оказалось легальным. Можно ли потом на этом куске памяти использовать delete[]?

Парадокс undefined behavior:

UD + UD = UD
UD * UD = UD

[sarcasm] Так что можешь не переживать ;) [/sarcasm]

KennyMinigun ★★★★★ ()
Ответ на: комментарий от normann

Выделить память под вектор (член класса)

Ты имеешь ввиду std::vector? Если да, то последний выделяет память под хранилище сам (и сам ею управляет). Но ты можешь использовать свой аллокатор.

KennyMinigun ★★★★★ ()
Ответ на: комментарий от KennyMinigun

мне это не надо объяснять. я это с начала 90-х знаю. я написала, про что конкретно была статья. и это именно то, что пытается делать ТС.

Iron_Bug ★★★★★ ()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от normann

Продолжай, если есть что сказать.

Мне нечего сказать, кроме «нет», а ты этого как будто не слышишь.

tailgunner ★★★★★ ()

В общем случае нельзя, потому что у тебя нет гарантии, что new вернёт тебе реальный адрес выделенной памяти, а не смещённый на сколько-то байт, которые он зарезервировал для служебной информации.

uuwaan ★★ ()
Ответ на: комментарий от Begemoth

Я немного не то имел в виду. Realloc внутри знает, есть ли за выделенным блоком свободное место. Оно не резервируется сразу, и может быть отдано при другом вызове malloc. Но если к моменту вызова realloc за указанным куском памяти есть достаточного размера свободное место, то аллокатору нет необходимости копировать память в другое место.

Это может дать какие-то проценты скорости; за ними и гонятся.

i-rinat ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Не malloc(), а ::operator new.

Зависит от цели. Я конкретно имел ввиду, что placement new может использовать какой-угодно участок памяти. А определение ::operator new для своих целей (аллокаторов) — отдельная история.

Кстати, на википедии хорошие примеры: https://en.wikipedia.org/wiki/Placement_syntax (если кому-то кроме нас с тобой интересно)

KennyMinigun ★★★★★ ()

realloc работает с памятью, выделенной через malloc. new выделяет память каким угодно способом, совсем не обязательно напрямую через malloc. Поэтому в общем случае нельзя. В частном случае может и будет работать, но это уже особенности реализации new на конкретном компиляторе в конкретном окружении.

Legioner ★★★★★ ()
Ответ на: комментарий от Legioner

Там терминология даже специальная есть, malloc/realloc работают с кучей, а new - с free store, и в общем случае эти две области не совпадают.

DELIRIUM ☆☆☆☆☆ ()

Перегрузи new/delete для своего типа в терминах malloc/free

Deleted ()

В общем случае нет.

Но если для всех тех сущностей, для которых нужен realloc(), ты можешь использовать свой allocator, то напиши свой аллокатор, который точно совместим с realloc() и используй только его.

pathfinder ★★★ ()
Ответ на: комментарий от xperious

В подавляющем большинстве случаев (на практике) это один хер, но ты можешь посмотреть стандарт найти там эти два определения.

DELIRIUM ☆☆☆☆☆ ()
Ответ на: комментарий от Iron_Bug

да память, выделенная через realloc - тоже

anonymous ()
Ответ на: комментарий от i-rinat

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

anonymous ()
Ответ на: комментарий от anonymous

А это тут причём? Память не по одной странице у системы запрашивается. По крайней мере, в glibc.

Допустим, у тебя была свободная память:

...........................................
Ты запросил блок вызовом malloc:
XXXXXXX....................................
Потом захотел поменять размер, позвал realloc:
XXXXXXXXXXXXXXX............................
Если то же делать без использования realloc, а с помощью комбинации malloc и free, будет:
XXXXXXXYYYYYYYYYYYYYYY.....................
.......YYYYYYYYYYYYYYY.....................

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

Другой момент — уменьшение размера выделенной памяти тем же realloc. Тут точно перемещать не нужно. Но как бонус аллокатор имеет возможность переиспользовать освободившуюся память для новых вызовов malloc. Без realloc для уменьшения выделенной памяти нужно будет копировать. Ну или всегда держать память выделенной, даже если она стала не нужна.

i-rinat ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.