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

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

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: как правильно прервать конструктор класса?  (Прочитано 20356 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« : Апрель 02, 2010, 18:26 »

Доброго времени.

У меня тут назрела небольшая непонятка: как прервать конструктор класса , если в нем произошла какая-либо ошибка?
т.е. нужно в таком случае сделать так, чтобы конструктор вернул НУЛЬ. ,
например:
Код:
...
//реализация
MyClass::MyClass()
{
    if (не выполняется какое-то условие) {
        тут прервать конструирование и вернуть НУЛЬ!
    }

}
...

//где-то в программе
    MyClass *c = new MyClass();
    //тут проверяем, создался ли объект или нет
    if (!c) {
      //тут завершаем программу
    }

т.е. чем прерывать конструктор?:
1. делать в нём return; ?
2. вызывать деструктор?
3. или как ?



Записан

ArchLinux x86_64 / Win10 64 bit
BRE
Гость
« Ответ #1 : Апрель 02, 2010, 18:37 »

т.е. чем прерывать конструктор?:
Конструктор можно прервать исключением.
Если не хочешь/не можешь использовать исключения, то можно использовать внутренний флаг валидности объекта. И проверять его после конструирования.
bool MyClass::isValid() const;
Записан
niXman
Гость
« Ответ #2 : Апрель 02, 2010, 18:40 »

в конструкторе, крайне нежелательно писать код, который может выполнится неправильно.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #3 : Апрель 02, 2010, 18:46 »

Цитировать
Если не хочешь/не можешь использовать исключения, то можно использовать внутренний флаг валидности объекта. И проверять его после конструирования.
bool MyClass::isValid() const;

т.е. имеется ввиду что-то вроде:

Код:
MyClass::MyClass()
{
    ....
    if (не выполняется какое-то условие) {
        m_valid = false;
        return;
    }
    ....
}

bool MyClass::isValid() const
{
    return m_valid;
}

//где-то в программе
    MyClass *c = new MyClass();
    //тут проверяем, создался ли объект или нет
    if (!c->isValid()) {
      //тут завершаем программу
    }
...

Непонимающий

Цитировать
в конструкторе, крайне нежелательно писать код, который может выполнится неправильно.

дык а если я в конструкторе класса создаю приватные объекты для этого класса, то как мне узнать что они создались корректно? если у них нет возможности проверить флаг валитности и т.п. то как быть?
« Последнее редактирование: Апрель 02, 2010, 18:53 от kuzulis » Записан

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

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Апрель 02, 2010, 18:51 »

Угу, оно самое.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #5 : Апрель 02, 2010, 18:54 »

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

т.е. если я создаю к примеру в конструкторе MyClass::Myclass():

Код:
   QSocketNotifier *notifier = new QSocketNotifier (this);

то как я узнаю, что notifier  создался правильно? ведь по-любому оператор new вернет указатель на память объекта - НО это не факт, что внутри у себя там объект проинициализировался корректно!
« Последнее редактирование: Апрель 02, 2010, 18:57 от kuzulis » Записан

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

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #6 : Апрель 02, 2010, 18:57 »

Опиши конкретнее ситуацию. Пример желателен.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Апрель 02, 2010, 19:05 »

Цитировать
Опиши конкретнее ситуацию. Пример желателен.
пример:

*.h
Цитировать
class Myslass : public QObject
{
    Q_OBJECT
public:
    Myslass(QObject *parent = 0);

private:
    QTimer *timer;

}

*.cpp
Цитировать
Myslass::Myslass(QObject *parent)
    : QObject(parent), timer(0)
{
    timer = new QTimer(this);

    //и вот тут нужно проверить, а валиден ли таймер?
    //ведь у класса QTimer нет методов для проверки его валидности!
    // т.е. объект timer то создастся, но как проверить "чисто гипотетически" будет ли он работать корректно?
   // вдруг  в конструкторе таймера пошло что-то не так??

}

вот чисто "гипотетический пример" , вместо таймера можно что угодно подставить Улыбающийся
Записан

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

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Апрель 02, 2010, 19:11 »

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

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Апрель 02, 2010, 19:16 »

Код:
   QSocketNotifier *notifier = new QSocketNotifier (this);

то как я узнаю, что notifier  создался правильно? ведь по-любому оператор new вернет указатель на память объекта - НО это не факт, что внутри у себя там объект проинициализировался корректно!
Обычно так

Код:
QSocketNotifier::QSocketNotifier( ..)
{
  ...
  if (somethingWrong)
    throw MyException();
  ...
}

// вызывающий
try {
    QSocketNotifier *notifier = new QSocketNotifier (this);
}
catch (MyException &) {
 notifier = 0;
}
catch (...) {
 ...
}
Хотя в Qt это не принято  Улыбающийся
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #10 : Апрель 02, 2010, 19:37 »

ок, спс.. будем разбираться
Записан

ArchLinux x86_64 / Win10 64 bit
SASA
Гость
« Ответ #11 : Апрель 03, 2010, 14:01 »

Пересмотри архитектуру, поизучай классы Qt, посмотри, как там сделано. Конкретно, вынеси из конструктора код, который может засбоить или используй флаг, это тебе уже говорили выше.
Я с опаской отношусь к прирыванию конструтора... Лучше разнести создание обьекта и инициализацию.
Код:
MyClass * m = MyClass();
bool b = m->init();
if (!b)
{
    /// Все плохо
}
...
MyClass::MyClass() {}
bool MyClass::init
{
     timer = new QTimer(this);

    //и вот тут нужно проверить, а валиден ли таймер?
    //ведь у класса QTimer нет методов для проверки его валидности!
    // т.е. объект timer то создастся, но как проверить "чисто гипотетически" будет ли он работать корректно?
   // вдруг  в конструкторе таймера пошло что-то не так??
   if (все плохо) rerurn false;

}
« Последнее редактирование: Апрель 03, 2010, 14:07 от SASA » Записан
Tonal
Гость
« Ответ #12 : Апрель 03, 2010, 15:05 »

Возбуждение исключения - самый правильный и надёжный способ в С++ прервать конструктор и сообщить что произошла ошибка.
При этом автоматом вызываются деструкторы  членов и базовых классов.
Естественно нужно позаботится об освобождение явно выделенных в конструкторе ресурсов.
Для этого можно модифицировать твой пример 2-мя способами:
 1. Использовать "умный" указатель для поля QTimer *timer.
Любой понравившийся из распространённых:
QPointer<QTimer> timer, std::auto_ptr<QTimer> timer, boost::scoped_ptr<QTimer> timer.
 2. Использовать "умные" указатели только внутри коснтруктора.
Для этого код коснтруктора разбивается на 2 области - реальная инициализация во временные переменные где может случится облом и установка полей, где обломов быть не может:
Код
C++ (Qt)
Myslass::Myslass(QObject *parent)
   : QObject(parent), timer(0), notifier(0)
{
   //Здесь могут происходить обломы
   std::auto_ptr<QTimer> timer = new QTimer(this);
   if (otherSomethingWrong)
       throw MyException();
   std::auto_ptr<QSocketNotifier> notifier = new QSocketNotifier (this);
   ....
   //Здесь обломов уже быть не может
   this->timer = timer.release();
   this->notifier = notifier.release();
}
 
В отличии от всяких флагов валидности, оба подхода гарантируют корректное освобождение ресурсов и защищают от работы с невалидным объектом
Записан
SABROG
Гость
« Ответ #13 : Апрель 06, 2010, 22:47 »

QPointer<QTimer> timer, std::auto_ptr<QTimer> timer, boost::scoped_ptr<QTimer> timer
...
В отличии от всяких флагов валидности, оба подхода гарантируют корректное освобождение ресурсов и защищают от работы с невалидным объектом

Вместо QPointer лучше QWeakPointer.
Цитировать
QWeakPointer is also more efficient than QPointer, so it should be preferred in all new code.

Я не согласен с тем, что флаг валидности плохое решение. Если QWeakPointer действительно сможет отлавливать невалидные объекты, то исключения тут даже не нужны, жертвовать переносимостью ради удобства лично я не буду.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Апрель 07, 2010, 04:41 »

Я не согласен с тем, что флаг валидности плохое решение. Если QWeakPointer действительно сможет отлавливать невалидные объекты, то исключения тут даже не нужны, жертвовать переносимостью ради удобства лично я не буду.
Не видно проблем переносимости т.к. исключения входят в стандарт языка. По поводу "флага валидности" - может и не плохо но что хорошего в нем мало - это точно. Поймать невалиднось и установить флаг легко, трудно с этим дальше работать. От объекта чего-то хотят, зовут его методы и.т.п. А тут выясняется что этот метод "не имеет должного эффекта" т.к. объект-то невалиден и обеспечить эту ф-циональность не может. А унаследовался от такого объекта - проверки валидности лезут в новые/перекрытые методы. В общем все это начинает неприятно быстро расползаться.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


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