Russian Qt Forum
Май 15, 2024, 23:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Почему не срабатывает блок try?  (Прочитано 23364 раз)
a_n_y_a
Гость
« Ответ #15 : Август 20, 2009, 13:45 »

Это продолжение темы
http://www.prog.org.ru/index.php?topic=10158.msg61489#msg61489
Только в родительском классе создается объект PotokThread и запускается на выполенение, его адрес при завершении программы проверяется на валидность. Вот там у меня грабли. Как мне проверить валидность указателя на объект?
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #16 : Август 20, 2009, 13:48 »

А зачем проверять валидность указателя на объект PotokThread при завершении работы приложения? Расскажи лучше, что нужно получить в итоге? Для чего эти проверки?
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Август 20, 2009, 14:28 »

Код:
if (ptr) ptr->doSomething();
Улыбающийся
Делаю:

if (ptr) printf("валидный указатель");
else printf("Не валидный указатель");
delete ptr;
printf(Удалили);

При ptr=NULL получаю:
Не валидный указатель
Удалили

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

И все, сообщение "Удалили" я не получаю, программа вылетает на delete ptr.
Как мне проверить, объект удален из памяти или нет? В программе с Qt ptr указывает на процесс.

Если Вы имеете указатель, то Вы же и ответственны за его корректность, язык в этом никак помочь не может. Стандартный подход: немедленно обнулить указатель после delete 

delete(ptr);
ptr = 0;

Чтобы полностью исключить его дальнейшее использование. Любые действия с уже удаленным указателем ведут к очень тяжелым последствиям (просто вылет = самое лучшее из них).  Ваш текст будет работать как Вы описали если, например, если вы вызвали delete второй раз для того же указателя. Использование exception в данном случае ничего не даст а только запутает: ptr может быть "корректным адресом" но данные по этому адресу уже разрушены, хуже того - этот адрес может уже используется для совершенно других данных.

Чтобы найти ошибку надо смотреть все что делается с указателем начиная с его создания (обычно new). Это может быть очень непросто но других методов нет.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #18 : Август 20, 2009, 14:59 »

Цитировать
if (ptr) printf("валидный указатель");
else printf("Не валидный указатель");
delete ptr;
printf(Удалили);

При ptr=NULL получаю:
Не валидный указатель
Удалили

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

И все, сообщение "Удалили" я не получаю, программа вылетает на delete ptr.
Как мне проверить, объект удален из памяти или нет? В программе с Qt ptr указывает на процесс.
1. Нужно было при самоудалении процесса обнулять указатель на него. По ходу два раза delete вызывается (как говорили выше)
   т.е. объект удалили, а указатель забыли обнулить, при этом в переменной ptr остался адрес удаленного объекта (но объекта уже не существует)! И может быть этот адрес уже используется другим процессом и т.п. Поэтому и вылетает! Улыбающийся (если я правильно понял ситуевину)
2. Не нужно при указателе = NULL  удалять его Улыбающийся

т.е. типо так нужно:
Код:
if (ptr) printf("валидный указатель");
else printf("Не валидный указатель");
if (ptr) {
    delete ptr;
    ptr=0;
    printf(Удалили);
}
« Последнее редактирование: Август 20, 2009, 15:02 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #19 : Август 20, 2009, 15:08 »

т.е наверное у вас что то типо этого:

Код:
class A 
{
public:
 ...
}

A *ptr1, *ptr2;

ptr1 = new A;
ptr2 = ptr1;

delete ptr1;
ptr1=0;

if (ptr2) printf("валидный указатель");
else printf("Не валидный указатель");
delete ptr2;
printf(Удалили);

при таком раскладе приложение вылетит

Записан

ArchLinux x86_64 / Win10 64 bit
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #20 : Август 20, 2009, 16:29 »

2. Не нужно при указателе = NULL  удалять его Улыбающийся

Абсолютно ничего не произойдет при:

Код
C++ (Qt)
ptr = 0;
...
delete ptr;
 


0-й указатель "удалять" можно.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
hamlo
Гость
« Ответ #21 : Август 20, 2009, 20:51 »

Код:
class A{
private:
int do_something(){ return 0; };
};

class B {

public:
B();

private:
A* a;
}

B::B(){
a=0

if(!a){
a = new A;
}
a->do_something;
}
Записан
a_n_y_a
Гость
« Ответ #22 : Август 21, 2009, 09:17 »

Вот код:

void Potok::ZapuskThread()
{
   Pt=new PotokThread((QObject*)this);
   connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));
   QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection);
    Pt->start();
};

Potok::~Potok()
{
   delete Pt;
};

Если происходит прерывание программы пока PotokThread не завершился, происходит утечка
памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его
валидность.
Записан
BRE
Гость
« Ответ #23 : Август 21, 2009, 09:25 »

Если происходит прерывание программы пока PotokThread не завершился, происходит утечка
памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его
валидность.
Это если в PotokThread запущен цикл обработки событий:
Код
C++ (Qt)
Potok::~Potok()
{
Pt->quit();
Pt->wait()
};
 

Если не запущен, нужно добавить код, который будет завершать нить и в деструкторе вызвать метод остановки потока и wait.
« Последнее редактирование: Август 21, 2009, 09:28 от BRE » Записан
spectre71
Гость
« Ответ #24 : Август 21, 2009, 09:26 »

Вот код:

void Potok::ZapuskThread()
{
   Pt=new PotokThread((QObject*)this);
   connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));
   QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection);
    Pt->start();
};

Potok::~Potok()
{
   delete Pt;
};

Если происходит прерывание программы пока PotokThread не завершился, происходит утечка
памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его
валидность.
После
connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));
Pt->start();
НЕЛЯЗЯ ДЕЛАТЬ!!!
delete Pt;
Может получить повторное удаление Pt! Это баг!

Если происходит прерывание программы система освобождает ресурсы связанные с ней и никакой утечки нет.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #25 : Август 21, 2009, 11:02 »

Если происходит прерывание программы пока PotokThread не завершился

Я уже предлагал вариант завершения потока при завершении работы приложения. Не подходит такой вариант?

Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
a_n_y_a
Гость
« Ответ #26 : Август 21, 2009, 12:16 »

Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль.  Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Август 21, 2009, 12:20 »

Вот код:

void Potok::ZapuskThread()
{
   Pt=new PotokThread((QObject*)this);
   connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));
   QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection);
    Pt->start();
};

Potok::~Potok()
{
   delete Pt;
};

Если происходит прерывание программы пока PotokThread не завершился, происходит утечка
памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его
валидность.

В С/C++ не существует способа проверить валидность указателя, надо полагаться на то что все операции с ним были корректны. В данном случае Вы перестарались и удаляете дважды  Улыбающийся  Одно из удалений надо убрать

Вариант 1
        PotokThread * Pt=new PotokThread((QObject*)this);
   connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));

Не делайте Pt членом класса, если deleteLater его грохнет, Вы остаетесь с уже удаленным указателем

Вариант 2 (по-моему лучше)
       // connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater()));  

Т.е. просто уберите/отключите эту строку. Остальное как у Вас, только в деструктор неплохо бы добавить

Potok::~Potok()
{
        if (Pt->IsRunning())
           Pt->exit();

   delete Pt;
}
Записан
BRE
Гость
« Ответ #28 : Август 21, 2009, 12:21 »

Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль.  Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы?
Я же тебе писал по поводу сигналов linux.  Непонимающий
man signal
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #29 : Август 21, 2009, 12:42 »

Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль.  Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы?
Немного толку от перехвата общего "в программе произошла ошибка". Ну перехватили и что будете делать? Данные уже наверняка искалечены, остается показать окно с извинениями и выйти (да и то неизвестно живы ли еще окна).  Имеет смысл перехватывать на каком-то участке, для этого есть try catch на любой платформе. Хотя перехват обращения по неверному адресу и возможен, это ошибка в программе которую надо исправлять, а не перехватывать
Записан
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.24 секунд. Запросов: 23.