Разбиение динамически размещенного массива без линейного копирования по времени

0

Я работаю со списком массива в C++, каждый в объекте и хотел разбить некоторые из них. Они распределяются динамически.

Я хотел сделать раскол в постоянное время, поскольку это теоретически возможно: из

[ pointer, size1 ] 

в

[ pointer, size2 ]; [ other array ]; [ pointer + size2, size1-size2 ]
(+ other data each time)

Я попытался использовать malloc и просто создать новый указатель, увеличенный с размером. Как и следовало ожидать, я получил ошибку из-за автоматического освобождения памяти.

Я попробовал realloc начиная со второго адреса, но, как и в "какой разница между malloc и calloc " на этом сайте, уже сказал мне, что это невозможно.

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

    class TableA
    {
     public:
      (constructor)
      void divide(int size); // the one i am trying to implement
      (other, geteur, seteur)
     private
      Evenement* _el;
      vector<bool>** _old;//said arrays
      int _size;
    }

ничего сложного

  • 2
    Вам нужно поставить код, ваше описание не очень понятно ...
  • 2
    Это вопрос C или C ++. Если последнее, вы, вероятно, вообще не должны использовать массивы malloc'd.
Показать ещё 1 комментарий
Теги:
arrays
malloc

5 ответов

0
Лучший ответ

Я не думаю, что вы можете иметь только часть динамического массива, освобожденную путем отслеживания указателей и длины. Однако вы можете подделать это, создав новый класс для управления стартовым массивом, выделив его, как вы хотите, и сохраните его с помощью std :: shared_ptr.

Вы просто возвращаете класс, содержащий shared_ptr в память, простой указатель на первый элемент и размер массива. Когда текущий класс Array выходит за пределы области действия, shared_ptr уменьшается, и когда больше не используются фрагменты памяти, память освобождается.

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

[Изменить] Ниже представлена очень простая реализация этой идеи. Оператор split() может быть легко реализован с помощью операций 2 slice(). Я не уверен, как вы хотите реализовать это с точки зрения вашего примера выше, так как я не уверен, как вы управляете своим vector<bool> **, но если вы хотите разделить vector<bool>, вы может создать экземпляр ShareVector<bool>, или если у вас есть массив vector<bool>, вместо этого сделайте SharedVector<vector<bool>>.

#ifndef __SharedVector__
#define __SharedVector__

#include <memory>
#include <assert.h>

template <typename T>
class SharedVector {

    std::shared_ptr<T> _data;
    T *_begin;
    size_t _size;
    // perhaps add size_t capacity if need for limited resizing arises.

public:
    SharedVector<T>(size_t const size)
    : _data(std::shared_ptr<T>(new T[size], []( T *p ) { delete[] p; })), _begin(_data.get()), _size(size)
    {}

    // standard copy and move constructors work fine

    // pass shared_ptr by reference to avoid unnecessary refcount changes
    SharedVector<T>(std::shared_ptr<T> &data, T *begin, size_t size)
    : _data(data), _begin(begin), _size(size)
    {}

    T& operator[] (const size_t nIndex) {
        assert(nIndex < _size);

        return _begin[nIndex];
    }  

    T const & operator[] (const size_t nIndex) const {
        assert(nIndex < _size);

        return _begin.get()[nIndex];
    }

    size_t size(){
        return _size;
    }

    SharedVector<T> slice(size_t const begin, size_t const end) {
        assert(begin + end < _size);

        return SharedVector<T>(_data, _begin + begin, end - begin);
    }

    T *begin() {
        return _begin;
    }

    T *end() {
        return _begin + _size;
    }
};

#endif
  • 0
    Спасибо за Ваш ответ. Я заметил в вашем коде '_data (std :: shared_ptr <int> (new int [size]'): используете ли вы int в качестве объекта с 1 октетом? Вместо этого будет работать char?
  • 0
    Ах, извините, это ошибка, конечно, это должно быть T, а не int. Спасибо за указание на это. Обратите внимание, что это сохраняет любую память, которую вы выделяете, это просто удобство доступа. Если вы создадите массив размером 100, разделите его на 2 из 50 и удалите один из них позже, у вас останется 100 выделенных элементов. Но вам не нужно беспокоиться об удалении данных позже, поскольку они удаляются, когда оригинал и другая разделенная часть уничтожаются.
1

В принципе, библиотека malloc не может справиться с mallocing куском памяти, а затем освобождение его фрагментов.

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

например

int* p = malloc(9 * sizeof(int));
int* q = p + 3;
int* r = p + 6;
// Now we have three pointers to three arrays of three integers.

// Do stuff with p, q, r

free(p); // p is the only pointer it is valid to free.

Кстати, если это действительно о C++, возможно, существуют стандартные структуры данных C++, которые вы можете использовать.

  • 0
    Знаете ли вы, как предотвратить другое, недействительное, бесплатное автоматическое использование после последнего использования объекта?
  • 0
    @wolfgangdurand Если память malloc распределяется между несколькими объектами, вам придется реализовать какой-то механизм, чтобы она не освобождалась до тех пор, пока последний объект не исчезнет. Будет работать какой-то механизм подсчета ссылок, но это действительно выглядит как плохой дизайн. Сделай шаг назад и подумай о лучшем пути.
Показать ещё 2 комментария
0

Вопрос относительно неясен

Но согласно вашей теме

разбиение динамически распределенного массива без линейной копии времени

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

  • 0
    Я также хочу использовать прямое обращение к массиву, улучшая решение, изначально основанное на списках. На самом деле, я знаю, что будет довольно мало сплиттов. Спасибо за предложение, тем не менее
0

Возможно, вы можете использовать std::copy.

int* p = (int*)malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++)
    p[i] = i;
for (int i = 0; i < 5; i++)
    std::cout << p[i];

// tmp will hold 3 values
// p2 will hold 2 values
// so we want to copy first 3 into tmp
// and last 2 into p2
int tmp[3];
std::copy(p, p+3, tmp);
for (int i = 0; i < 3; i++)
    std::cout << tmp[i];
int p2[2];
std::copy(p+3, p+5, p2);
for (int i = 0; i < 2; i++)
    std::cout << p2[i];
// get rid of original when done
free(p);

Вывод:

0123401234
  • 0
    memcopy, std :: copy ... являются линейными копиями, стоимость которых увеличивается с размером. Я хочу иметь операцию с постоянным временем, которая, я знаю, теоретически возможна
  • 0
    @wolfgangdurand, это только линейно, если ваши объекты не следуют стандартному расположению (то есть не POD). Если они делают, то это фактически заканчивается копированием одного куска памяти в другой, конечно, время будет меняться в зависимости от размера указанного куска памяти, но это примерно столько же времени, сколько вы можете получить ..
Показать ещё 1 комментарий
0

Я думаю, что malloc и создать новую идею указателя хорошо. Но вам нужно освободить память вручную, я думаю.

  • 0
    Это была моя первая попытка, но я не знаю, как предотвратить освобождение деструктора объекта: у меня было несколько сбоев или ошибок сегментации, связанных с этим
  • 0
    Вы пытались вручную освободить указатель, который вы используете для выделения исходного массива? Не тот, который вы используете, чтобы указать начало второго массива.
Показать ещё 10 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню