2015-06-01 2 views
1

У меня проблема с моим кодом. Я хочу передать значение из моего массива указателей на функцию, чтобы исходный объект не был «нарушен» (мой код работает отлично, если я передаю ссылку, я просто пытаюсь сделать это иначе, как упражнение по обучению). После возвращения реализации я получаю сообщение об ошибке:Деструктор тестового класса для выделенного указателя?

Ошибка для объекта 0x100105790: указатель освобожден не был назначен *** установить точку останова в malloc_error_break для отладки ".

Я знаю, что это потому, что, поскольку значение выходит за пределы области действия при возврате функции, деструктор вызывается для объекта, но мой деструктор принимает указатель, который был выделен, таким образом, ошибка. Мне было любопытно, есть ли способ проверить, был ли уже выделен геном или нет. Если бы я не сделал что-то еще для деструктора? Это даже проблема, о которой стоит беспокоиться, поскольку у меня уже есть ее работа, передавая ссылку? Функция на самом деле не разрушительна; У меня просто есть желание сделать некоторые трюки. Мне не нравится принимать легкий выход.

//class destructor for int genome[] 
Organism::~Organism() { 
    //cout << "Deleting this: " << this << endl; 
    if (this->genome != NULL) { 
     delete [] this->genome; 
    } 
} 

//declare genome pointer 
int *genome; 
/** 
* Default constructor for class 
*/ 
Organism::Organism() { 
    this->fitness = 0; 
    this->size = 0; 
    this->genome = NULL; 
} 
//another constructor for if only the size of genome is defined 
Organism::Organism(int size) { 
    this->fitness = 0; 
    this->size = size; 
    this->genome = new int[size]; 
} 
//another constructor for when all starting values are defined 
Organism::Organism(int size, int *genome) { 
    this->fitness = 0; 
    this->size = size; 
    this->genome = new int[size]; 

    for (int i = 0; i < size; i++) { 
     this->genome[i] = genome[i]; 
    } 
} 

//initialize and populate reproducible from already existing array start_pop  (this has been verified as being properly allocated and values initiated) 
vector<Organism*> reproduceable (0); 
    for (int i = 0; i < start_pop.size(); i++) { 
     if (start_pop[i]->get_fitness() > threshold) { 
      reproduceable.push_back(start_pop[i]); 
     } 
    } 

//function definition 
Organism* reproduce(Organism, Organism); 

//function call in main() 
offspring.push_back(reproduce(*reproduceable[i], *reproduceable[i+1])); 

//function implementation 
Organism* reproduce(Organism a, Organism b) { 
    int genome[4]; 

    //randomly decide on where to split parent genomes 
    int split = rand() % 5; 
    for (int i = 0; i < a.get_size(); i++) { 
     if (i < split) { 
      genome[i] = a.get_genome()[i]; 
     } else { 
      genome[i] = b.get_genome()[i]; 
     } 
    } 
    //now cause random mutation in 2% of the population 
    if ((rand() % 100 + 1) <= 2) { 
     int rand_index = rand() % 5; 
     int mutation = rand() % 6 + 1; 

     genome[rand_index] = mutation; 
    } 

    Organism *child = new Organism(4, genome); //need to add genome 
    return child; 
} 

Edited добавить конструктор по умолчанию и инициализацию массива для воспроизводимой

+0

Что такое Организм :: геном? Где он назначен? – isanae

+1

Поскольку единственное 'delete' находится в деструкторе и пытается освободить массив' genome', возможно, вы никогда не выделяете его 'new', следовательно, ошибка. Не могли бы вы разместить там, где вы инициализируете «воспроизводимую» структуру и инициализацию «генома» внутри «Организма»? – Alejandro

+0

Как выглядит ваш конструктор? – vsoftco

ответ

1

Вашей проблемы в этой строке:

offspring.push_back(reproduce(*reproduceable[i], *reproduceable[i+1])); 

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

Organism* reproduce(Organism a, Organism b) 

Он ожидает, что два Organism «S значением, что означает, что для обоих Organism» ы будем называть конструктор копирования. Поскольку вы не определяете конструктор копирования, будет создан по умолчанию, который просто копирует содержимое одного организма в другой, в том числе указатель на геном. Проблема в том, что теперь будут освобождены и Organism s - тот, который является локальным для этой функции, и тот, который был передан в нее, что приводит к двойному освобождению памяти, выделенной для генома. Есть два способа решить эту проблему:

  1. Сделать подпись быть
Organism* reproduce(const Organism &a, const Organism &b) 

Таким образом, ваш Organism не будет скопирован, и, таким образом, не будет двойной освобожден. (по вашему вопросу, я полагаю, вы уже пробовали это и заинтересованы во втором решении :))

  1. Внедрить собственный конструктор копий, который создает новый массив, например
Organism::Organism(const Organism& a) 
{ 
    this->fitness = a.fitness; 
    this->size = a.size; 
    this->genome = new int[this->size]; 
    for (int i = 0; i < this->size; ++ i) 
     this->genome[i] = a.genome[i]; 
} 

Таким образом, как вы передаете организм в вашу функцию, пользовательский конструктор копирования будет вызван, и genome для организма локального вашей функции будет выделен отдельно.

+0

Спасибо! Работает как шарм! Я до сих пор не понимал важность конструктора копирования. – bj7

1

Правило трех

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

см http://en.cppreference.com/w/cpp/language/rule_of_three

Хотя лучше было бы правило нуля, т.е. вы обнимаете семантику значений.
Для этой программы было бы так просто, как изменяя genome член от int* к
int[4], std::array<int,4> или std::vector<int>
(и удалить деструктор)

Смежные вопросы