Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Проблема с динамической памятью  (Прочитано 4822 раз)
0 Пользователей и 1 Гость смотрят эту тему.
romeo
Гость
« : 01-03-2009 11:19 » 

День добрый!
Возникла проблема с динамической памятью: имеется класс Chromosome и глобальная функция FitnessFunct, которая в качестве аргумента принимает экземпляр данного класса. Даже если тело функции пустое (как ниже в листинге), то при вызове этой функции при выполнении вылетает ошибка типа "Unhandled exception at 0x10252758 (msvcr80d.dll) in DebugProj.exe: 0xC0000005: Access violation reading location 0xfeeefee2."
Причем ошибка возникает при выходе из функции main.  Т.е. тело FitnessFunc выполняется корректно, а ошибка связана именно с передачей класса в функцию. Подскажите пожалуйста в чем ошибка. Здесь была моя ладья...

Код:
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <ctime>
#include "Chromosome.h"

using namespace std;

int Chromosome::GeneQty; //добавил, чтобы однажды задавался размер хромосомы для всех ее экземпляров
int Chromosome::GeneSize; //без этого проблемы с линкером

double FitnessFunct(Chromosome Chr)
{
double temp_FR=0;
return temp_FR;
}

int main()
{
int r=5, z=2;
srand(time(0));
Chromosome::SetDim(r,z);

Chromosome a;
FitnessFunct(a);

return 0;
}

Класс Chromosome
Код:
#include <iostream>
#include <ctime>
#include "math.h"

using namespace std;

class Chromosome
{
bool **Chromos;
static int GeneQty, GeneSize;



public:
Chromosome ();
~Chromosome();

static void SetDim(int GQty, int GSize)
{
GeneQty = GQty;
GeneSize = GSize+2;
}
};

Chromosome::Chromosome()//создание пустой хромосомы, как массива генов
{
Chromos = new bool* [GeneQty];
for (int i=0; i<GeneQty; i++)
{
Chromos[i] = new bool[GeneSize];
};
for (int l=0; l<GeneQty; l++)
        for (int j=0; j<GeneSize; j++)   
   Chromos[l][j]= false;

}

Chromosome::~Chromosome()
{
for(int i=0; i<GeneQty; i++)
delete [] Chromos[i];
delete [] Chromos;

}
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 01-03-2009 13:00 » 

ошибка тут:
Код:
for (int l=0; l<GeneQty; l++)
        for (int j=0; j<GeneSize; j++)   
   Chromos[l][j]= false;

надо
Код:
Chromos = new bool* [GeneQty];
for (int i=0; i<GeneQty; i++)
{
Chromos[i] = new bool[GeneSize];
::memset(Chromos[i],0,sizeof(*Chromos[i])*GeneSize);
};

а вот так Chromos[l ][j ]
к такому массиву вообще нельзя обращаться, так как массив - не сплошной
« Последнее редактирование: 01-03-2009 13:02 от Алексей1153++ » Записан

Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #2 : 01-03-2009 13:12 » 

romeo, Ты раньше писал программы на Паскале?

Вот я привел твой код к С стилю
main.cpp
Код:
#include <iostream>
#include <stdlib.h>
#include <ctime>
#include "Chromosome.h"


using namespace std;


double FitnessFunct(Chromosome &Chr)
{
double temp_FR=0;
return temp_FR;
}

int main()
{
int r=5, z=2;
srand(time(0));
Chromosome::SetDim(r,z);

Chromosome a;
FitnessFunct(a);

return 0;
}

Chromosome.h
Код:
#ifndef CHROMOSOME_H
#define CHROMOSOME_H


class Chromosome
{
bool **Chromos;
static int GeneQty, GeneSize;



public:
Chromosome ();
~Chromosome();

static void SetDim(int GQty, int GSize)
{
GeneQty = GQty;
GeneSize = GSize+2;
}
};

#endif // CHROMOSOME_H

Chromosome.cpp
Код:
#include "Chromosome.h"

int Chromosome::GeneQty; //добавил, чтобы однажды задавался размер хромосомы для всех ее экземпляров
int Chromosome::GeneSize; //без этого проблемы с линкером


Chromosome::Chromosome()//создание пустой хромосомы, как массива генов
{
Chromos = new bool* [GeneQty];
for (int i=0; i<GeneQty; i++)
{
Chromos[i] = new bool[GeneSize];
};
for (int l=0; l<GeneQty; l++)
        for (int j=0; j<GeneSize; j++)  
  Chromos[l][j]= false;

}

Chromosome::~Chromosome()
{
for(int i=0; i<GeneQty; i++)
delete [] Chromos[i];
delete [] Chromos;

}

1) Экземпляры классов передаются в функцию по ссылке или по указателю на них.
2) Не лепи в хедер реализацию класса, вынеси его в отдельный файл.
3) Обязательно закрывай хедер ключами от повторного использования.
4) Очень плохая идея, позволять изменять динамически размерность массива, Изменение будет касаться сразу всех экземпляров класса. Что может привести к трудно выловимым глюкам. Для учебной лабы в принципе и так сойдет. Для проекта нужно менять логику.
« Последнее редактирование: 01-03-2009 13:45 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 01-03-2009 13:13 » 

Алексей1153++, Это будет работать, и так можно обрашаться.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #4 : 01-03-2009 14:03 » 

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

romeo
Гость
« Ответ #5 : 03-03-2009 09:15 » 

Благодарю - ошибка исправлена!

Цитата
1) Экземпляры классов передаются в функцию по ссылке или по указателю на них.
2) Не лепи в хедер реализацию класса, вынеси его в отдельный файл.
3) Обязательно закрывай хедер ключами от повторного использования.
4) Очень плохая идея, позволять изменять динамически размерность массива, Изменение будет касаться сразу всех экземпляров класса. Что может привести к трудно выловимым глюкам. Для учебной лабы в принципе и так сойдет. Для проекта нужно менять логику.

Finch, а почему нельзя оставить реализацию класса в хедере? вроде логично в одном файле описать целиком класс с реализацией. А так только множить количество файлов.
Еще вопрос - для чего надо закрывать хедер ключами? чем чревато повторное использование?
А по поводу динамического изменения размерности массива, так мне и надо чтобы все экземпляры были одинакового размера. Просто константой я не могу задать, т.к. размер может меняться (но для всех экземпляров). Как тогда в этом случае лучше будет сделать?
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #6 : 03-03-2009 10:03 » 

и снова велосипед.
vector

проблема с включением хедеров  в том, что иногда один и тот же хедер тянется из кучи мест и если он таки включется дважды
то в одной единице трансляции(выучить термин) может несколько определений и объявлений одних и техже переменных/функций/классов, эту проблему лечас "стражами"
почему реализацию отделяют от декларации? потому что тогда методы класса будут компилироваться в каждом cpp в который влючен хедер, допускается так делать если все методы класса реализованы в объявлении класс в противном слачае, при линковке получишь ошибку "Функция реализована в нескольких объектных файлах"
Записан

Странно всё это....
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 03-03-2009 12:12 » 

И еше добавлю, что в больших проектах, значительно быстрее компилируется проект когда хедеры отделены от реализации. На твоем примере это просто не заметно. Разница будут составлять несколько десятков микросекунд. Тебе просто нужно понять логику компиляции. Компилируется каждый .cpp файл в отдельности. Компиляция происходит в два этапа. Сначала предкомпиляция. Когда все include заменяются содержимым хедеров. Раставлются все макроопределения и так далее. Затем уже происходит сама компиляция. И на выходе получается объектный файл. После успешной компиляции всех .cpp файлов, происходит линковка всех полученных объектных файлов. На выходе получается уже запускаемый экзешник. Теперь представь, что ты один и тот же код заставляеш компилироваться несколько раз, если скажем ты свой Chromosome.h включил в несколько файлов проекта.
Ну и чисто эстетические соображения. Намного легче изучать, что содержит  класс, если в хедере он приведен без реализации. Потом уже по мере надобности, можно и взглянуть и на саму реализацию.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
romeo
Гость
« Ответ #8 : 15-03-2009 15:59 » 

Спасибо за разъяснения:) теперь понятно.

Еще вопрос возник: как правильно передать в функцию массив экземпляров класса Chromosome?
Т.е. я передаю в функцию сортировки так
            void SortArray(Chromosome *mas).
Но экземпляры класса надо же передавать по ссылке. Как правильно написать?  void SortArray(Chromosome *&mas) не работает.
ЗЫ: может покажется смешным, но у меня с этим сложности((


Точнее проблема возникает, когда я при сортировке меняю местами элементы массива (которые являются экземплярами класса). Т.е. например
Код:
Chromosome mas[2];
mas[0] = mas [1];
Что мне делать? перегружать оператор присваивания?
« Последнее редактирование: 15-03-2009 17:17 от Алексей1153++ » Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 15-03-2009 18:51 » 

Массив ты уже передаёшь. Ничего больше изобретать не надо - ведь указатель на память ты, наверное, модифицировать не собираешься, а потому сам указатель вполне можно передавать по значению.

По поводу обмена - да, либо перегружать оператор, либо подумать над самой структурой - я имею в виду массив с элементами нетривиальной структуры. Если нужна скорость работы - то, возможно, стоит хранить в массиве не сами значения, а указатели на элементы, и переупорядочивать эти указатели - тогда не потребуется копирование элементов. В противном случае - перекрывать оператор копирования.
« Последнее редактирование: 15-03-2009 18:55 от Вад » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines