realloc
— функция стандартной библиотеки C для изменения размера ранее выделенного блока памяти. Её сигнатура:
void* realloc(void* ptr, size_t new_size);
Ключевые особенности:
Потенциальное сохранение указателя
При расширении памяти может не потребоваться копирование, если после текущего блока есть свободное место
Эффективность для POD-типов
Для тривиальных типов можно избежать лишних копирований:
template<typename T>
void vector<T>::resize(size_t new_size) {
static_assert(std::is_trivial_v<T>, "T must be trivial type");
T* new_data = static_cast<T*>(realloc(data_, new_size * sizeof(T)));
if (!new_data) throw std::bad_alloc();
data_ = new_data;
}
Снижение фрагментации памяти
По сравнению с malloc/free парами
Только для trivial-типов
Не вызывает конструкторы/деструкторы:
// Опасный пример для нетривиальных типов
std::string* arr = static_cast<std::string*>(malloc(10 * sizeof(std::string)));
realloc(arr, 20 * sizeof(std::string)); // UB!
Проблемы совместимости
Разные аллокаторы могут не поддерживать realloc
Потеря данных при ошибке
Если realloc вернет NULL, исходный блок останется валидным
template<typename T>
class PodVector {
static_assert(std::is_pod_v<T>, "T must be POD type");
T* data_;
size_t size_;
size_t capacity_;
public:
void reserve(size_t new_capacity) {
if (new_capacity <= capacity_) return;
T* new_data = static_cast<T*>(realloc(data_, new_capacity * sizeof(T)));
if (!new_data) throw std::bad_alloc();
data_ = new_data;
capacity_ = new_capacity;
}
```PodVector() {
free(data_);
}
};
class CString {
char* data_;
public:
void append(const char* str) {
size_t new_len = strlen(data_) + strlen(str) + 1;
char* new_data = static_cast<char*>(realloc(data_, new_len));
if (!new_data) throw std::bad_alloc();
strcat(new_data, str);
data_ = new_data;
}
};
Собственный аллокатор с realloc
template<typename T>
class ReallocAllocator {
public:
T* reallocate(T* ptr, size_t old_size, size_t new_size) {
if constexpr (std::is_trivial_v<T>) {
return static_cast<T*>(realloc(ptr, new_size * sizeof(T)));
}
// Для нетривиальных типов - стандартное поведение
T* new_ptr = allocate(new_size);
// ...
}
};
Использование memory_resource в C++17
Можно реализовать polymorphic_allocator с поддержкой realloc-подобной функциональности
Пример сравнения для std::vector<int>
vs PodVector<int>
:
| Операция | realloc-версия | Обычный vector | Выигрыш |
|----------------|----------------|----------------|---------|
| push_back 1M | 12ms | 18ms | 33% |
| resize 2x | 8ms | 15ms | 47% |
Проверка типа
template<typename T>
void safe_realloc(T*& ptr, size_t new_size) {
static_assert(std::is_trivially_copyable_v<T> &&
!std::is_const_v<T>, "Invalid type for realloc");
// ...
}
Обработка ошибок
T* new_data = static_cast<T*>(realloc(data_, new_size));
if (!new_data && new_size != 0) {
// Сохраняем старый указатель для восстановления
throw std::bad_alloc();
}
Резюмируем: realloc может дать значительный прирост производительности в специализированных контейнерах для POD-типов, но требует осторожного использования и не подходит для объектов с нетривиальной семантикой. В современных C++ проектах его применение оправдано в узких сценариях оптимизации.