Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.56/18: Рейтинг темы: голосов - 18, средняя оценка - 4.56
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814

Исключение в конструкторе шаблонного класса

15.03.2017, 10:58. Показов 3942. Ответов 43

Студворк — интернет-сервис помощи студентам
Добрый день!
Пишу класс дробей и, соответственно, если пользователь введёт 0 в знаменатель с помощью оператора >> или с помощью конструктора с 2мя параметрами, то нужно вызвать исключение. Но как это сделать, я не понимаю.

Fraction.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
template <class T>
class Fraction {
 
    public:
        Fraction();
        Fraction(T n, T d);
        ~Fraction();
 
        template <class T>
        friend const Fraction<T>& lowterms(Fraction<T>& fraction);
 
        //I/O operators
        template <class T>
        friend std::istream& operator >> (std::istream& stream, Fraction<T>& fraction);
        template <class T>
        friend std::ostream& operator << (std::ostream& stream, const Fraction<T>& fraction);
 
        //THROWS
        class denominatorEqualsToZero {};
 
    private:
        T numerator;
        T denominator;
 
};
 
template <class T>
Fraction<T>::Fraction(T n, T d) : numerator(n) {
 
    if (d == 0) {
 
        throw denominatorEqualsToZero();
 
    }  else {
 
        denominator = d;
 
    }
 
    lowterms(*this);
 
}


Сделал так, но при генерации исключения возникает ошибка "Возникло необработанное исключение по адресу ... исключение Microsoft C++: Fraction<int>::denominatorEqualsToZero ..."

Скажите, пожалуйста, как правильно выполнять исключения в конструкторах и, тем более, в шаблонных.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.03.2017, 10:58
Ответы с готовыми решениями:

Инициализация шаблонного класса(В конструкторе класса после двоеточия вновь имя класса)
Всем доброго времени суток! Пытаюсь разобраться как работает приведенный мной код. Конкретно, пытаюсь разобраться что происходит в...

Параметр const T & val = T() в конструкторе шаблонного класса
Добрый день! Начал разбираться с шаблонами и наткнулся на такой пример: template &lt; typename T &gt; struct my_class { ...

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

43
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
15.03.2017, 11:03
Nishen, не знаю, поможет ли, но есть спец. форма try для конструкторов
C++
1
2
3
4
5
6
7
8
A::A(const B& b) try : mB(b) 
{ 
    // constructor stuff
}
catch (/* exception type */) 
{
    // handle the exception
}
1
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
15.03.2017, 11:15  [ТС]
Всё равно необработанное исключение.

Добавлено через 6 минут
А такой подход к реализации будет верен? Вместо исключения просто информировать пользователя об ошибке:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class T>
Fraction<T>::Fraction(const T& n, const T& d) : numerator(n) {
 
    if (d == 0) {
 
        std::cerr
            << "Denominator cannot be equals to zero!"
            << std::endl;
 
        denominator = 1;
 
    } else {
 
        denominator = d;
 
    }
 
    lowterms(*this);
 
}
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 12:03
Nishen,
Мб объявить конструктор так:
C++
1
Fraction(T n, T d) noexcept(throw denominatorEqualsToZero());
?
0
192 / 128 / 52
Регистрация: 19.01.2010
Сообщений: 518
15.03.2017, 12:07
Цитата Сообщение от Nishen Посмотреть сообщение
Всё равно необработанное исключение.
создание объекта обернуть в трай-кэч
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
15.03.2017, 12:12
Цитата Сообщение от Nishen Посмотреть сообщение
Сделал так, но при генерации исключения возникает ошибка "Возникло необработанное исключение по адресу
ну дык, вы ж сами хотели его кидать.
вы его и кинули.
вот оно и вылетело.


Цитата Сообщение от Nishen Посмотреть сообщение
Скажите, пожалуйста, как правильно выполнять исключения в конструкторах и, тем более, в шаблонных.
вы все правильно сделали.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 12:15
Цитата Сообщение от GbaLog- Посмотреть сообщение
Мб объявить конструктор так:
Фигню какую-то написал, можно просто: Fraction(T n, T d) noexcept(false);
Да и дело не в этом...
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
15.03.2017, 12:25
Вы осторожнее с исключениями в конструкторе
Если конструктор бросается исключением и это исключение "ловится" вне конструктора - в таком случае деструктор не вызывается потому что объект по факту не был создан

Но до выброса исключения вы могли занять память присваивая полям объекта определенные значения
Это уже будет утечкой памяти
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
 
struct Foo
{
    int *n;
    Foo(int num)
    {
        
        n = new int(num);
        if (num < 10)
            throw "aaa";
    }
    ~Foo()
    {
        delete n;
        std::cout << "Destructor";
    }
};
 
int main(){
  
    
    try {   
        Foo f(5);
    } catch (...){}
}
Как видим деструктор не вызвался
1
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 12:28
Цитата Сообщение от sys_beginner Посмотреть сообщение
Вы осторожнее с исключениями в конструкторе
Пока нет сырых указателей - всё норм, RAII работает.
2
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
15.03.2017, 12:30  [ТС]
Всё, я понял, в чём была моя ошибка.
Если делать так, как у меня в первом коде, при этом обернув создание объекта в try - catch, то создание объекта не произойдёт, верно? Т.е. не нужно же нигде потом самому память вычищать?
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
15.03.2017, 12:34
Цитата Сообщение от GbaLog- Посмотреть сообщение
Пока нет сырых указателей - всё норм, RAII работает.
Мне вот интересно. По идее деструктор уничтожаемого объекта занимается вызовом деструкторов своих полей
Но если деструктор не сработал, каким образом вызывается деструкторы объектов которые созданы не в динамической памяти? Просто за счет того что область видимости заканчивается?
0
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
15.03.2017, 12:35  [ТС]
Цитата Сообщение от sys_beginner Посмотреть сообщение
это исключение "ловится" вне конструктора
Как в моей ситуации можно поймать исключение и обработать его в самом конструкторе?

Я вообще, почему-то не уверен, что мой подход к реализации верен.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 12:37
Цитата Сообщение от sys_beginner Посмотреть сообщение
Просто за счет того что область видимости заканчивается?
Типа того, throw вызывает раскрутку стека до catch, ну или если catch нету, до std::terminate, при этом все автоматические объекты вызывают деструкторы.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
15.03.2017, 12:40
Цитата Сообщение от Nishen Посмотреть сообщение
Т.е. не нужно же нигде потом самому память вычищать?
Если сущности были созданы в динамической памяти - то это приведет к утечке

Добавлено через 3 минуты
Цитата Сообщение от Nishen Посмотреть сообщение
Как в моей ситуации можно поймать исключение и обработать его в самом конструкторе?
Просто написать try/catch внутри конструктора
Но в вашем случае лучше не кидать исключения

А еще лучше перед тем как создаете объект сделайте проверку - если число подходит для создания объекта тогда создавайте, если нет то - не создавайте

А то получается вам перед созданием объекта известно что объект с этими данными не может существовать, но при этом вы все равно пытаетесь его создать
Как то не логично, согласитесь
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
15.03.2017, 12:43
Цитата Сообщение от Nishen Посмотреть сообщение
Как в моей ситуации можно поймать исключение и обработать его в самом конструкторе?
называется "создать проблем себе на задницу".

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

если вы не можете решить эту проблему - тогда кидаем исключение.

и уже парни снаружи конструктора будут его ловить,
и решать проблему.

------

вкратце:
самому кидать исключение в конструкторе
и самому же в конструкторе его ловить - это какой то бред.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 12:44
Nishen, Можете в компайл тайм перенести
http://rextester.com/RUAIC4921
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//g++  5.4.0
 
#include <iostream>
 
template<typename Tp, Tp n, Tp d>
struct Fraction
{
    static_assert(d != 0, "Denominator cannot be equals to zero!");
};
 
int main()
{
    std::cout << "Hello, world!\n";
    
    Fraction<int, 1, 0> f;
}
Ну или просто поставить ассерт в конструкторе и забить на то, что кто-то может ввести 0.
Ну или сделать конструктор по-умолчанию и метод init, в котором можно смело бросать экзепшоны.
0
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
15.03.2017, 13:00  [ТС]
Цитата Сообщение от sys_beginner Посмотреть сообщение
А еще лучше перед тем как создаете объект сделайте проверку - если число подходит для создания объекта тогда создавайте, если нет то - не создавайте
А то получается вам перед созданием объекта известно что объект с этими данными не может существовать, но при этом вы все равно пытаетесь его создать
Как то не логично, согласитесь
Я согласен с Вами.
Но если я, например, пишу библиотеку. Тот, кто будет пользоваться ею и не подозревает может быть, что знаменатель дроби не может ровняться нулю. Как в таком случае мне предупредить его о том, что он создает объект с невозможными значениями?
Опять же, я не могу просто взять и заменить введенный пользователь нуль единицей, например, и продолжить выполнение программы, как ни в чём не бывало (я это делал тут).

Цитата Сообщение от hoggy Посмотреть сообщение
если в своём конструкторе вы пофиксили проблему,
и знаете как можно её порешать
Как бы Вы решили эту проблему в конструкторе?
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
15.03.2017, 13:05
У вас же есть конструктор по умолчанию?
Тогда так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename Tp>
Fraction<Tp> createFraction(Tp n, Tp d)
{
    if (d == 0)
    {
        std::cerr << "error\n";
        return Fraction<Tp>();
    }
    else
    {
        return Fraction<Tp>(n, d);
    }
}
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
15.03.2017, 13:23
Nishen,
Если пишите библиотеку тогда наверное исключения будут верным решением.
Но при этом нужно всячески избегать создания объектов в динамической памяти до того момента, пока существует вероятность того, что будет брошено исключение
Иначе будет утечка

Добавлено через 33 секунды
Цитата Сообщение от GbaLog- Посмотреть сообщение
У вас же есть конструктор по умолчанию?
Тогда так:
А если наличие объекта не имеет смысла в случае когда число не валидное?
Выходит будут сделаны лишние операции
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
15.03.2017, 14:48
Цитата Сообщение от Nishen Посмотреть сообщение
Как бы Вы решили эту проблему в конструкторе?
C++
1
2
3
4
5
6
#include <cassert>
 
....
 
 
assert(d != 0 && "Denominator cannot be equals to zero!");
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
15.03.2017, 14:48
Помогаю со студенческими работами здесь

Исключение в конструкторе класса
Всем здравствуйте! Что будет с классом, если в его конструкторе вылетело и не перехватилось исключение. Например: ...

Как корректно передать в метод шаблонного класса объект шаблонного класса в качестве параметра?
header.h template &lt;class T&gt; class MyVector { public: void swap(MyVector&lt;T&gt;Vector); } template &lt;class T&gt; void...

Вызов метода у шаблонного поля, шаблонного класса
Пытаюсь разобраться с шаблонами- задача создать шаблонный класс, у которого есть шаблонное поле. и затем вызывать метод у этого поля. ...

В конструкторе копирования отцовского (_str) класса возникает некое "необработанное исключение"
Добрый день. Делаю курсовик в универе, иерархия классов и работа с ними. В конструкторе копирования отцовского (_str) класса возникает...

Возможно ли создание объекта шаблонного класса в функции этого класса?
Доброго времени суток, уважаемые форумчане :) Мне по лабам задали задание - реализовать шаблон контейнера (множество) с операциями...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru