Указатель на удаление массива - PullRequest
0 голосов
/ 13 октября 2010

У меня есть массив, который передается через функцию и присваивается члену класса, который является указателем.

class ClassA{

unsigned char * pointerToArray;

ClassA(unsigned char array[]){
    pointerToArray = array; 
}

~ClassA(){
    //what to do here   
}
};

Теперь у меня есть второй класс, который использует это

class ClassB {
std::list<ClassA> classAcollection;

void firstFunction(){
    for(int i = 0; i < 5; i++){
        unsigned char buffer[3000];
        somePopulationFunction(&buffer);
        classAcollection.push_back(ClassA(buffer);
    }
}

void secondFuncion(){
    std::list<ClassA>::iterator it;

    for(it = classAcollection.begin(); it != classAcollection.end(); it++)
    {
        classAcollection.erase(it);
    }      
}                              
};

У меня вопрос, как сделать так, чтобы pointerToArray каждый раз удалялся classAcollection.erase (it) .

Я не могу добавить вызов удаления в деструкторе ClassA, так как получаю ошибку: освобождаемый указатель не выделен

Ответы [ 3 ]

3 голосов
/ 13 октября 2010

Ваше первое предложение уже показывает всю путаницу:

Привет, у меня есть массив, который передается через функцию и присваивается члену класса, который является указателем.

Вы не можете "передать массив". Вы можете передавать указатели или ссылки на массивы или элементы массива в функции. Тип параметра array в конструкторе для ClassA фактически является типом указателя. Это правила C, которые уже запутывают достаточно людей. Обязательно ознакомьтесь с хорошими учебниками по массивам и указателям.

Вот что действительно происходит в вашем коде:

  • Вы создаете массив с автоматической продолжительностью хранения внутри первой функции,
  • Вы заполняете его данными.
  • Вы передаете указатель на первый элемент массива в конструктор ClassA :: ClassA
  • Итерация завершена, массив перестает существовать, и шаги 1-3 повторяются еще 4 раза

Проблема: все объекты ClassA имеют недопустимый элемент-указатель, потому что все массивы, на которые они ссылались, теперь исчезли.

Если вы хотите, чтобы эти массивы пережили свою область, это требует динамического выделения. Вы можете динамически выделять массив и «передавать владение» объекту ClassA . Под «владением» мы обычно подразумеваем ответственность за управление и удаление массива. Это возможно, и другие ответы покажут вам, как к этому подойти. Но они на самом деле неполные. Видите ли, если вы хотите, чтобы объект класса управлял таким ресурсом, как память, вам нужно сделать больше, чем просто предоставить деструктор. Вы также должны позаботиться о копировании. Это означает, что конструктор копирования и оператор присваивания. Поскольку вы не только создаете объект класса ClassA, но и используете его в качестве аргумента для функции push_back списка, список создаст копию и сохранит / будет управлять этой копией. Таким образом, если вы все еще хотите заставить ClassA правильно управлять буфером, сохраняя простой (немой) указатель, вы должны написать ctor копии, оператор присваивания и деструктор, потому что в противном случае они были бы сгенерированы компилятором. А сгенерированные компилятором просто копируют по элементам. Полагаю, вы не хотите, чтобы два отдельных объекта ClassA совместно использовали один и тот же буфер, верно?

Вместо обработки необработанных указателей вы можете просто использовать вектор как ClassA member:

class ClassA
{
    std::vector<unsigned char> buffer;
public:
    ClassA(unsigned char const* begin, unsigned char const* end)
    : buffer(begin,end)
    {}
};

:
:

void firstFunction()
{
    for(int i = 0; i < 5; i++) {
        unsigned char buffer[3000];
        somePopulationFunction(&buffer);
        classAcollection.push_back(ClassA(buffer+0,buffer+3000));
    }
}

Это работает, потому что std :: vector не ведет себя как указатель. Если вы копируете вектор, копия будет управлять своими собственными элементами. Там нет обмена. В этом отношении вектор работает больше как обычный int или double. Обычно это реализуется в терминах указателей. Но это похоже на «обычный тип значения».

Здесь мы мало что можем сделать. ClassA должен быть копируемым, если вы хотите поместить ClassA объекты в список. Поэтому трудно избежать копирования и в то же время избежать совместного использования буферов между ClassA объектами.

В C ++ 0x (кодовое имя для будущего стандарта C ++) вы сможете сделать это:

class ClassA
{
    std::vector<unsigned char> buffer;
public:
    ClassA(unsigned char const* begin, unsigned char const* end)
    : buffer(begin,end)
    {}
    ClassA(ClassA const&) = default;
    ClassA(ClassA &&) = default;
    ClassA& operator=(ClassA const&) = default;
    ClassA& operator=(ClassA &&) = default;
};

Это создаст класс, который будет копируемым и «подвижным». Класс с включенным перемещением обычно очень эффективно передается из и в функции. В вашем примере объект ClassA является временным объектом. Как таковой, он может быть быстро перемещен в список без какого-либо ненужного копирования объектов буфера. Но это только то, что тебя дразнит. C ++ 0x еще не официально.

1 голос
/ 13 октября 2010
   void firstFunction(){
        for(int i = 0; i < 5; i++){
            unsigned char * buffer = new unsigned char[3000];
            somePopulationFunction(&buffer);
            classAcollection.push_back(ClassA(buffer);
        }
    }

и

~ClassA(){
    delete [] pointerToArray;   
}
0 голосов
/ 13 октября 2010

Измените

unsigned char buffer[3000];

на

unsigned char* buffer = new unsigned char[3000];

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

Добавьте

delete [] pointerToArray;

в деструктор, чтобы убедиться, что память очищена.И почитайте разницу между операторами «удалить» и «удалить []»

...