Страница 1 из 2
Удаление динамических потомков
Добавлено: 30 июн 2016, 20:08
Skwoogey
Код: Выделить всё
class module
{
...
};
class memory: public module
{
...
};
int main()
{
//module *p;
//p = new memory;
memory a;
//p->solved = p->interface();
a.solved = a.interface();
//cout << p->solved << endl;
cout << a.solved << endl;
//delete p;
return 0;
}
Если объект создается динамически, то иногда программа крашится при удалении объекта. при обычном создании объекта программа завершается корректно. Деструкторы сделал виртуальными. В чем дело понять не могу. Нужна помощь. Заранее спасибо.
Re: Удаление динамических потомковж
Добавлено: 01 июл 2016, 14:49
Romeo
По первым описанным признакам, а также по тому, что удаление объекта полиморфное, первая же мысль была о том, что деструктор не сделан виртуальным в базовом классе. Но раз этот факт отдельно оговорен, то нужна дополнительная информация о том, что там скрыто в трёх точках. В частности, что за поле solved и что за метод interface?
Re: Удаление динамических потомковж
Добавлено: 01 июл 2016, 14:56
Skwoogey
содержимое модуля:
Код: Выделить всё
public:
int solved;
int answer;
int tried;
//simple_wires
int wires_num;
wires w[6];
//button
int colour;
int name;
//simon_says
int sequence[6];
int seq_length;
int cur_beat;
//memory
int stage;
int answer_type;
int screen_number;
int button_numbers[4];
int previous_stages[][2];
int virtual right_answer()
{
}
int virtual interface()
{
}
virtual ~module()
{
cout << "mod" << endl;
}
содержимое класса "memory":
Код: Выделить всё
public:
memory()
{
stage = 1;
tried = 1;
solved = 0;
}
virtual ~memory()
{
cout << "mem" << endl;
}
int interface()
{
while(stage != 6)
{
if(tried)
{
screen_number = rand() % 4 + 1;
for(int i = 0; i < 4; i++)
{
int bak = rand() % 4 + 1;
int additional = 0;
for(int j = 0; j < i; j++)
{
if(button_numbers[j] == bak)
{
bak = (bak % 4) + 1;
j = -1;
}
}
button_numbers[i] = bak;
}
}
tried = 0;
switch(stage)
{
case 1:
{
answer_type = POSITION;
if((screen_number == 1) || (screen_number == 2))
answer = 2;
if(screen_number == 3)
answer = 3;
if(screen_number == 4)
answer =4;
break;
}
case 2:
{
answer_type = POSITION;
if((screen_number == 4) || (screen_number == 2))
answer = previous_stages[0][POSITION];
if(screen_number == 1)
{
answer = 4;
answer_type = NUMBER;
}
if(screen_number == 3)
answer =1;
break;
}
case 3:
{
answer_type = NUMBER;
if(screen_number == 1)
answer = previous_stages[1][NUMBER];
if(screen_number == 2)
answer = previous_stages[0][NUMBER];
if(screen_number == 3)
{
answer = 3;
answer_type = POSITION;
}
if(screen_number == 4)
answer =4;
break;
}
case 4:
{
answer_type = POSITION;
if(screen_number == 1)
answer = previous_stages[0][POSITION];
if(screen_number == 2)
answer = 1;
if((screen_number == 3) || (screen_number == 4))
{
answer = previous_stages[1][POSITION];
}
break;
}
case 5:
{
answer_type = NUMBER;
if(screen_number == 1)
answer = previous_stages[0][NUMBER];
if(screen_number == 2)
answer = previous_stages[1][NUMBER];
if(screen_number == 3)
answer = previous_stages[3][NUMBER];
if(screen_number == 4)
answer = previous_stages[2][NUMBER];
break;
}
}
//system("cls");
cout << "strikes: " << strikes << endl;
cout << "stage: " << stage << endl;
cout << "answer_type: " << answer_type << endl;
cout << "answer: " << answer << endl;
cout << "prev_pos: " << previous_stages[stage-2][POSITION] << endl;
cout << "prev_num: " << previous_stages[stage-2][NUMBER] << endl;
cout << "screen" << endl;
cout << "| " << screen_number << " |" << endl << endl;
cout << "buttons" << endl;
cout << "| ";
for(int i = 0; i < 4; i++)
{
cout << button_numbers[i] << " | ";
}
cout << endl << endl;
cout << "type button position" << endl;
char player_answer;
scanf("%c", &player_answer);
getchar();
cout << endl;
if(player_answer == 'q')
return 0;
tried = 1;
switch(answer_type)
{
case POSITION:
if(((int)player_answer - 48) == answer)
{
previous_stages[stage - 1][POSITION] = answer;
previous_stages[stage - 1][NUMBER] = button_numbers[answer - 1];
stage++;
}
else
{
strikes++;
stage = 1;
}
break;
case NUMBER:
if(button_numbers[(int)player_answer - 49] == answer)
{
previous_stages[stage-1][POSITION] = (int)player_answer - 48;
previous_stages[stage-1][NUMBER] = answer;
stage++;
}
else
{
strikes++;
stage = 1;
}
break;
}
}
return 1;
}
Чтобы было понятнее, это я для проекта в институте "портирую" игру "keep talking and nobody explodes" на командную строку.
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 00:12
Romeo
Во-первых, ничего критичного и могущего привести к крашу я не обнаружил.
Во-вторых, после того, как засунул сей опус в cpp файл, поправил какое-какие места (так как не хватало дефайнов) и вернул полиморфное создание/удаление объекта, то у меня всё отработало без краша.
В-третьих, очень интересует вопрос, а зачем тут вообще базовый класс нужен, и кто тебя учил инициализировать поля базового класса в конструкторе производного?
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 00:25
Skwoogey
если просто сразу выходить с помошью "Q", то все нормально, если немного поиграться, то крашится.
Про дефайны чего-то сразу не додумался кинуть. Вот все на всякий случай.
Код: Выделить всё
#define GREEN 0
#define BLUE 1
#define YELLOW 2
#define RED 3
#define BLACK 4
#define WHITE 5
#define ABORT 1
#define DETONATE 2
#define HOLD 3
#define P_R 0
#define H_R 1
#define POSITION 0
#define NUMBER 1
Базовый класс нужен, чтобы для бомбы рандомные модули генерировать, но держать их в одном массиве указателей.
Сообщили о том, что классы вообще существуют, мне в институте, Все азы в интернете узнал, а дальше сам экспериментировал. А инициализация переменных базового в производном плохой тон или что?
Я тут еще поэкспериментировал, просто вводя 2 как ответ: начинает крашится после 4 введеных 2. После 3, не получилось.
Я до того как обратиться сюда за помощью, поискал в интернете на эту тему. Встретил подобную ситуацию, но она вроде так и осталась неразрешенной.
http://www.programmersforum.ru/showthread.php?t=165992
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 00:55
Romeo
А что такое за поле strikes и что за тип wires? Слушай, может всё сложишь в один файлик, проверишь, что компилируется и выложишь сюда, чтобы я мог забрать к себе и собрать? А то занимаюсь гаданием на кофейной гуще...
И да, инициализация полей базового класса в конструкторе наследника - это очень-очень плохой тон. Поля базового класса должен инициализировать конструктор базового класса. К сожалению, это не единственное спорное место в этом коде. Там таких мест куча. Но сейчас хочется лучше на них не обращать внимания. Для начала нужно понять причину краша.
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 01:03
Skwoogey
Вот. В мейне у меня там много различных тестов в комментариях лежат, но тест с указателями не закомментирован.
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 02:06
Romeo
Получилось воспроизвести. Судя по тому, как дебагер показывает виртуальную таблицу в деструкторе module, ты портишь указатель на виртуальную таблицу, оперируя с полями. Скорее всего где-то едешь по памяти, вылезая за границы массива.
В качестве проверки, можешь закомментить тело solve_interface и обратить внимание, что краш пропадает, так что виноват именно проезд по памяти, а не то, что неправильно работают виртуальные деструкторы.
Более подробно определять проблемное место сейчас лень, так как ночь уже и пора на боковую.
Чтобы точнее узнать место, которое нужно исправить, комментируй кусками проблемный метод и каждый раз пробуй воспроизвести проблему. Как только воспроизводимость меняется, значит ты только что закомментил/раскомментил искомый код.
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 02:29
Skwoogey
Нашел. Я случайно забыл указать один из размеров массива previous_stages, и у меня там просто были пустые скобки. Я удивлен, что он вообще заработал. Насколько я знаю пустые скобки можно оставлять только если сразу инициализируешь. Спасибо за помощь. Я вроде репутацию повысил, но не уверен (После 4PDA все такое непривычное, так что скажите если я ошибся). Еще есть просьба: можете рассказать о хорошем тоне кодинга? Все,что я слышал в институте, это соблюдать табуляцию и не использовать goto.
Re: Удаление динамических потомковж
Добавлено: 02 июл 2016, 11:13
Romeo
Ну, в двух словах о правильном проектировании рассказать просто не получится.
На данный момент у тебя не соблюдается даже принцип
инкапсуляции, а ведь это один из трёх базовых столпов
ООП. Данные должны сокрываться в классе. В идеале в секции public должны быть расположены только методы. Мотивацию смотри в статье.
Следующий шаг - разобраться с принципами
SOLID.
Когда с базой всё будет в порядке, то если захочешь расти дальше, нужно уже читать книги. Начать можно с чего-нибудь не очень тяжелого, например "Рефакторинга" Фаулера. Благо книга не новая, так что доступна для бесплатного скачивания, например
тут. Есть и парочка других книжек этого же уровня, названия которых легко гуглятся. Хотя, в принципе, и одного Фаулера будет достаточно.
После ещё одного левел апа, уже следует браться за более серьёзное чтиво, а именно за шаблоны проектирования. Вкратце о них можно почитать на
вики, но там очень сжато и непонятно зачем вообще это нужно. Лучше, конечно, будет прочитать книгу знаменитой "банды четырёх". Залакировать можно будет книжкой
"Рефакторинг с использованием шаблонов" Джошуа Кириевски.
Последние две книги по шаблонам это уже уровень опытного разработчика.
И это только чтиво по архитектуре. По хорошему нужно ещё и язык постигать. Здесь нужно читать Страуструпа, Майерса и даже Александреску (только последнего крайне осторожно, чтобы не сломать голову). Полный список книг, который обязан прочесть любой уважающий себя разработчик С++ состоит из около десятка произведений.
P.S. По поводу репутации. У тебя всё получилось. Этой кнопочкой народ так толком и не научился пользоваться, так как админы что-то намутили, и после смены пары движков форума, как у нас сейчас работает репутация, не понимает почти никто
