Форум программистов, компьютерный форум CyberForum.ru

Работает ли указатель на базовый класс исключения, когда попадает в блок catch - C++

Восстановить пароль Регистрация
 
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 04:04     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #1
Работает ли указатель на базовый класс исключения, когда попадает в блок catch так же как обычно? То есть, если есть переопределенные вирутальные методы, то искользуется ли нужный?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.08.2014, 04:04     Работает ли указатель на базовый класс исключения, когда попадает в блок catch
Посмотрите здесь:

C++ typeid определяет тип указателя на базовый класс, как тип "базовый класс". Вне зависимости от присвоенного ему значения
Иерархия классов и указатель на базовый класс C++
C++ Виртуальное наследование (указатель на базовый класс)
Как передать управление в блок catch после системного исключения (компилятор g++)? C++
C++ Указатель на базовый класс и на производный
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
__SOKOL__
3 / 3 / 0
Регистрация: 29.06.2013
Сообщений: 107
06.08.2014, 04:26     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #2
Ты вот это имеешь ввиду?
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <string>
#include <windows.h>
 
using namespace std;
 
 
class A
{
public:
    virtual void test() { cout << "class A" << endl; }
};
 
class B : public A
{
    virtual void test() override { cout << "class B" << endl; }
};
 
int main()
{
    
    try
    {
        B* b = new B;
        throw b;
    }
    catch(A* a)
    {
        a->test();
        delete a;
    }
    
    return 0;
}

Это работает, срабатывает переопределённый метод.
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 04:39  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #3
Немного другое.
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
// exc_mean.h  -- exception classes for hmean(), gmean()
#include <iostream>
 
class base_excep: public std::logic_error 
{
private:
    double a;
    double b;
public:
    base_excep(double val1 = 0, double val2 = 0, const char* s = "Unknow exception") :a(val1), b(val2), logic_error(s) {}
    virtual ~base_excep() {}
    void what_arg() const { std::cout << "Arguments: " << a << " " << b << std::endl; }
};
 
class bad_hmean: public base_excep
{
private:
    const char* str;
public:
    bad_hmean(double val1 = 0, double val2 = 0, const char* s = "Function: hmean(). Invalid arguments: a = -b\n") : str(s), base_excep(val1, val2, s) {}
};
 
class bad_gmean :public base_excep
{
private:
    const char* str;
public:
    bad_gmean(double val1 = 0, double val2 = 0, const char* s = "Funtion: gmean(). Arguments should be >= 0\n") : str(s), base_excep(val1, val2, s) {}
};
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
43
44
45
46
47
48
49
50
51
//error4.cpp – using exception classes
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include "exc_mean.h"
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
    
    double x, y, z;
 
    cout << "Enter two numbers: ";
    while (cin >> x >> y)
    {
        try {                  // start of try block
            z = hmean(x,y);
            cout << "Harmonic mean of " << x << " and " << y
                << " is " << z << endl;
            cout << "Geometric mean of " << x << " and " << y
                << " is " << gmean(x,y) << endl;
            cout << "Enter next set of numbers <q to quit>: ";
        }// end of try block               
        catch (base_excep* excep) 
        {
            cout << excep->what();
            excep->what_arg();
            cout << "Sorry, you don't get to play any more.\n";
            break;
        } // end of catch block
    }
    cout << "Bye!\n";
    return 0;
}
 
double hmean(double a, double b)
{
    if (a == -b)
        throw &bad_hmean(a,b);
    return 2.0 * a * b / (a + b);
}
 
double gmean(double a, double b)
{
    if (a < 0 || b < 0)
        throw &bad_gmean(a,b);
    return std::sqrt(a * b); 
}
Тут вызывается what() со строкой определенной в logic_eror. В случае ссылки все хорошо.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 05:06     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #4
Gwini, а Вы какого результата ожидаете, пытаясь брать адрес временного объекта?
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 05:09  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #5
Цитата Сообщение от 0x10 Посмотреть сообщение
Gwini, а Вы какого результаат ожидаете, пытаясь брать адрес временного объекта?
можно поподробнее?
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 05:11     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #6
Gwini, в 42 и 49 строках создается временный объект, у которого нельзя взять адрес, ибо он rvalue. По логике пример даже скомпилироваться не должен.
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 05:16  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #7
Цитата Сообщение от 0x10 Посмотреть сообщение
в 42 и 49 строках создается временный объект, у которого нельзя взять адрес, ибо он rvalue. По логике пример даже скомпилироваться не должен.
но все же компилируется. Ссылка работает, как я понимаю, из за того что создается копия согласно механизму исключений. Какие вообще правила действуют к указателям, а то в книжке которую я читаю есть только про ссылки.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 05:20     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #8
Цитата Сообщение от Gwini Посмотреть сообщение
Ссылка работает, как я понимаю, из за того что создается копия
Ссылки используют как раз чтобы объект исключения лишний раз не копировался.
Можно думать об обработчике catch как о функции - передача аргументов аналогичная.

Добавлено через 2 минуты
Цитата Сообщение от Gwini Посмотреть сообщение
но все же компилируется
Чем?
MrCold
851 / 749 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
06.08.2014, 05:21     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #9
Gwini,
имеется ввиду ссылка здесь
C++
1
catch (base_excep & excep)
Добавлено через 57 секунд
или через new исключение бросить
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 05:24  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #10
Цитата Сообщение от 0x10 Посмотреть сообщение
Ссылки используют как раз чтобы объект исключения лишний раз не копировался
Как это? Прата пишет что объект копируется в любом случае. И по вашей логике если это временный объект то тогда не на что и ссылатся.

Добавлено через 1 минуту
Цитата Сообщение от 0x10 Посмотреть сообщение
Чем?
Visual Studio
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 05:27     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #11
Gwini, пример для иллюстрации:
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
#include <iostream>
 
struct MyException {
    MyException() {
        std::cout << "default ctor" << std::endl;
    }
 
    MyException(const MyException& ex) {
        std::cout << "copy ctor" << std::endl;
    }
};
 
int main() {
    std::cout << "catch by value" << std::endl;
 
    try {
        throw MyException();
    } catch (MyException ex) {
        std::cout << "catch\n" << std::endl;
    }
 
    std::cout << "catch by cref" << std::endl;
 
    try {
        throw MyException();
    } catch (const MyException& ex) {
        std::cout << "catch" << std::endl;
    }
}
Вывод:
Код
$ ./a.out
catch by value
default ctor
copy ctor
catch

catch by cref
default ctor
catch
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 05:50  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #12
Я наверное чего то не понимаю, но все же на что тогда ссылатся если объект временный? И как поннимать написаное в книге?
Миниатюры
Работает ли указатель на базовый класс исключения, когда попадает в блок catch  
CyberSolver
 Аватар для CyberSolver
101 / 74 / 17
Регистрация: 23.07.2014
Сообщений: 686
Записей в блоге: 1
06.08.2014, 06:56     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #13
Gwini, g++ это даже не скомпилировал:
Код
In file included from error4.cpp:4:0:
exc_mean.h:12:13: error: looser throw specifier for ‘virtual base_excep::~base_excep()’
     virtual ~base_excep() {}
             ^
In file included from exc_mean.h:3:0,
                 from error4.cpp:4:
/usr/include/c++/4.8/stdexcept:64:13: error:   overriding ‘virtual std::logic_error::~logic_error() throw ()’
     virtual ~logic_error() _GLIBCXX_USE_NOEXCEPT;
             ^
error4.cpp: In function ‘double hmean(double, double)’:
error4.cpp:42:29: error: taking address of temporary [-fpermissive]
         throw &bad_hmean(a,b);
                             ^
error4.cpp: In function ‘double gmean(double, double)’:
error4.cpp:49:29: error: taking address of temporary [-fpermissive]
         throw &bad_gmean(a,b);
Плюс вы нарушаете правило «используй только константные ссылки для исключений». Если бы вы бросили исключение через new — это ещё ладно, хотя тоже плохо. Но вы используете ссылку на локальный объект, т.е. объект на стеке. При обработке исключения стек раскручивается, локальные объекты уничтожаются — т.е. даже если бы ваш код скомпилировался, вы получите указатель на мусор.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 07:26     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #14
Цитата Сообщение от Gwini Посмотреть сообщение
Я наверное чего то не понимаю, но все же на что тогда ссылатся если объект временный?
Попробую описать по рабоче-крестьянски, не претендуя на точность в формулировках.

В примере кода, который прводил я, создается временный объект, который компилятор "удерживает" в процессе раскрутки стека.
В Вашем примере есть еще локальный объект на стеке. Его компилятор удерживать не может, потому что при раскрутке стека вызываются деструкторы локальных объектов, поэтому необходимо создать еще один объект, который и будет протаскиваться по стеку вызовов.

Далее перехватить этот объект можно по значению - тогда будет создана еще одна копия, а можно по ссылке - тогда лишнего копирования не будет, что и показывает пример в посте 11.
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
06.08.2014, 11:29     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #15
Цитата Сообщение от 0x10 Посмотреть сообщение
а можно по ссылке - тогда лишнего копирования не будет, что и показывает пример в посте 11.
эээ...ну тут уж смотря чем и как компилировать
http://codepad.org/MbpfRkH3
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
06.08.2014, 11:38     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #16
Jupiter, вот пичаль. А все равно во втором случае на одно копирование меньше
DrOffset
6422 / 3796 / 878
Регистрация: 30.01.2014
Сообщений: 6,585
06.08.2014, 13:40     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #17
Цитата Сообщение от Gwini Посмотреть сообщение
Прата пишет что объект копируется в любом случае.
В данном случае объект - это указатель. Он и копируется.

Цитата Сообщение от MrCold Посмотреть сообщение
или через new исключение бросить
Лучше не надо.

Цитата Сообщение от CyberSolver Посмотреть сообщение
error: taking address of temporary [-fpermissive]
В более ранних версиях GCC (например в 3.3.6) это не было ошибкой. Выдавался warning.
В общем случае компилятор вооще не обязан трактовать это как ошибку, т.к. в стандарте нет конкретных указаний что считать ошибкой, а что предупреждением. Поэтому можно считать что оба компиляторы корректно себя ведут.

Цитата Сообщение от Gwini Посмотреть сообщение
Visual Studio
Даже предупреждения не было?

Цитата Сообщение от 0x10 Посмотреть сообщение
вот пичаль.
Там похоже оптимизация отключена или на минимуме.

Цитата Сообщение от Gwini Посмотреть сообщение
Я наверное чего то не понимаю, но все же на что тогда ссылатся если объект временный?
Надо бросать по значению, тогда созданный временный объект скопируется в спец. область памяти, и будет доступен для передачи в catch после раскрутки стека (по ссылке или по значению). Через new создавать исключения - можно, но не нужно, т.к. появляется много подводных камней, которые делают ситуацию небезопасной. В книге написано все правильно, просто то, что передано throw всегда компируется по значению. Т.е. если передан указатель, то будет скопирован указатель (и только), если передан объект класса, то будет скопирован объект класса и т.п.
Gwini
10 / 10 / 3
Регистрация: 08.03.2014
Сообщений: 70
06.08.2014, 17:10  [ТС]     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #18
Цитата Сообщение от DrOffset Посмотреть сообщение
Даже предупреждения не было?
нет

Добавлено через 7 минут
Болле того выводит сообщение, используя метод базового класса(унаследованого от logic_error) и метод what() класса logic_error.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.08.2014, 19:27     Работает ли указатель на базовый класс исключения, когда попадает в блок catch
Еще ссылки по теме:

Создание объекта через указатель на базовый абстрактный класс C++
C++ Вызов виртуальной функции через указатель на базовый класс
Вызов метода производного класса через указатель на базовый класс C++

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

Или воспользуйтесь поиском по форуму:
DrOffset
6422 / 3796 / 878
Регистрация: 30.01.2014
Сообщений: 6,585
06.08.2014, 19:27     Работает ли указатель на базовый класс исключения, когда попадает в блок catch #19
Цитата Сообщение от Gwini Посмотреть сообщение
Болле того выводит сообщение, используя метод базового класса(унаследованого от logic_error) и метод what() класса logic_error.
Есть такое выражение:
Правильно работающая программа - частный случай Undefined Behaviour.
Как раз твой случай.

Добавлено через 2 минуты
Цитата Сообщение от Gwini Посмотреть сообщение
нет
Надо бы повысить уровень предупреждений в настройках проекта. И отключить от греха расширения компилятора, по крайней мере на время обучения.
Yandex
Объявления
06.08.2014, 19:27     Работает ли указатель на базовый класс исключения, когда попадает в блок catch
Ответ Создать тему
Опции темы

Текущее время: 01:24. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru