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

setjump/longjump - C++

Восстановить пароль Регистрация
 
yoghurt92
373 / 344 / 22
Регистрация: 17.05.2012
Сообщений: 1,049
03.02.2013, 19:40     setjump/longjump #1
Доброго времени суток! Занимаюсь по книге Дейтелей и встретил задание на setjump/longjump. Вот оно:

При использовании setjump и longjump программа может сразу передавать управление подпрограмме ошибки из глубоко вложенной функции. К сожалению, в этом случае при разматывание стека не вызываются деструкторы автоматических объектов, которые были созданы в течение последовательных вложенных вызовов функций. Напишите программу, которая показывает, что эти деструкторы действительно не вызываются.

Моя проблема с функциями, не может кто-нибудь подробно объяснить как с ними работать, в книги примера работы нет, гугл особо не помог... заранее спасибо!
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Пёс
 Аватар для Пёс
228 / 76 / 4
Регистрация: 03.02.2013
Сообщений: 311
03.02.2013, 20:08     setjump/longjump #2
Тебе нужно написать несколько классов, в деструкторах которых будет чтото вроде
C++
1
2
3
4
~Class()
{
   cout << "сработал деструктор класса Class";
}
вызвать некоторое количество вложенных функций, потом прервать их. и посомтреть в консоль. Если деструктор не был вызван, то там не будет надписи.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
03.02.2013, 20:34     setjump/longjump #3
Баловаться с #if в 34 строке (0 или 1).
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
52
53
54
55
56
#include <iostream>
#include <setjmp.h>
 
class RecurseGuard {
    int &token;
public:
    RecurseGuard(int &token)
      : token(token)
    {
        token++;
        std::cout << "> ";
        for (int i = 0; i < token; i++) {
            std::cout << ".";
        }
        std::cout << "\n";
    }
 
    ~RecurseGuard()
    {
        std::cout << "< ";
        for (int i = 0; i < token; i++) {
            std::cout << ".";
        }
        std::cout << "\n";
        token--;
    }
};
 
jmp_buf xen;
 
int fact(int n, int &token)
{
    RecurseGuard _(token);
#if 0
    if (n == 3) {
        longjmp(xen, 0);
    }
#endif
    if (n > 0) {
        return n * fact(n - 1, token);
    }
    else {
        return 1;
    }
}
 
int main()
{
    if (!setjmp(xen)) {
        int token = 0;
        std::cout << fact(10, token) << "\n";
    }
    else {
        std::cout << "Exception!\n";
    }
}
Добавлено через 7 минут
Ах да, как работать.

Шаг 1: #include <setjmp.h>

Шаг 2: Объявить где-то переменную типа jmp_buf. Сюда будет сохраняться стек, который нужен для переходов.

Шаг 3: Сохранить стек с помощью setjmp(переменная типа jmp_buf). setjmp возвращает 0, если она сохранила стек туда, и не 0, если это был переход сюда из-за longjmp.

Шаг 4: Где надо вызвать longjmp(переменная типа jmp_buf, какое-то значение). После этого будет выполнен переход (goto) туда, где setjmp() сохранила стек. setjmp() при этом вернёт то значение, которое было передано в longjmp() (если был ноль, то вернёт единичку). Дальше выполнение продолжается как ни в чём не бывало с того места, где стоит setjmp(). Если setjmp() вызывалась из какой-то функции, которая была вызвана откуда-то ещё, то все аргументы, локальные переменные и порядок возвратов из функций будет такой же, каким должен быть.

Идиома применения setjmp() — вон тот иф, где одна ветка соответствует продолжению исполнения, а другая — возврату по longjmp().

Ага, это что-то вроде исключений, только тормознутее и плевало на весь Си++ с его деструкторами, его исключениями и т. п.
yoghurt92
373 / 344 / 22
Регистрация: 17.05.2012
Сообщений: 1,049
03.02.2013, 21:13  [ТС]     setjump/longjump #4
~OhMyGodSoLong~, что-то на бред какой-то похоже... все запутанно... если для моего примера брать, то правильно ли я понимаю, я например, создал 3 функции, пускай будет f1, f2, f3 и характер их вызовов f1 -> f2 -> f3, и получается мне нужно в мейне вызвать одну из этих функций и прыгнуть из нее?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
03.02.2013, 21:38     setjump/longjump #5
Ну вот создаёте пачки функций a1, a2, a3 и b1, b2, b3. Они вызывают друг друга по цепочке: a1 > a2 > a3 и b1 > b2 > b3. Ещё сделайте какой-то класс, у которого конструкторы-деструкторы пишут гадости в std::cout, чтобы можно было отследить их вызовы. В каждую из тех шести функций засунтье по локальной переменной этого типа.

Функция a3 пусть вызывает выход из себя с помощью исключения: throw в ней и обернуть вызов a1 из main в try-catch.

Функция b3 пусть вызывает выход из себя с помощью setjmp/longjmp: longjmp(...) в ней и if (!setjmp(...)) в main вокруг вызова b1.

А потом смотрите на разницу в том, что выводится.
yoghurt92
373 / 344 / 22
Регистрация: 17.05.2012
Сообщений: 1,049
04.02.2013, 00:17  [ТС]     setjump/longjump #6
~OhMyGodSoLong~, вот сделал вроде по аналогии с вашим кодом(что вы дали), но видно не судьба мне...

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
52
53
54
#include "stdafx.h"
#include <iostream>
#include <locale.h>
#include <setjmp.h>
using namespace std;
 
class A
{
    private:
        int a, b;
 
    public:
        A():a(4), b(5) {}
        ~A() {  wcout << L"Деструктор А\n"; }
        void print()
        {
            wcout << "a: " << a << "\tb: " << b << "\n\n";
        }
};
 
jmp_buf xen;
 
void fun3(void)
{
    A c;
    longjmp(xen, 0);
}
 
void fun2(void)
{
    A b;
    fun3();
}
 
void fun1(void)
{
    A a;
    fun2();
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    wcout.imbue(locale(".866"));
    wcin.imbue(locale(".866"));
 
    if (!setjmp(xen)) {
        fun1();
    }
    else {
        std::cout << "Exception!\n";
    }
 
    return 0;
}
Заранее благодарю!

Добавлено через 1 час 33 минуты
~OhMyGodSoLong~, сделал по другому и вроде все работает, спасибо Вам за помощь но возник другой вопрос, вот код:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// obr.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <iostream>
#include <locale.h>
#include <setjmp.h>
using namespace std;
 
class A
{
    private:
        int a, b;
 
    public:
        A():a(4), b(5) {wcout << L"Конструктор А\n";}
        ~A() {  wcout << L"Деструктор А\n"; }
        void print()
        {
            wcout << "a: " << a << "\tb: " << b << "\n\n";
        }
};
 
class B
{
    private:
        int a, b;
 
    public:
        B():a(4), b(5) {}
        ~B() {  wcout << L"Деструктор B\n"; }
        void print()
        {
            wcout << "a: " << a << "\tb: " << b << "\n\n";
        }
};
 
class C
{
    private:
        int a, b;
 
    public:
        C():a(4), b(5) {}
        ~C() {  wcout << L"Деструктор C\n"; }
        void print()
        {
            wcout << "a: " << a << "\tb: " << b << "\n\n";
        }
};
 
jmp_buf xen;
 
void fun3(void)
{
    longjmp(xen, 0);
    A a1;
}
 
void fun2(void)
{
    fun3();
    B b2;
}
 
void fun1(void)
{
    fun2();
    C c1;
}
 
void fun6(void)
{
    throw A();
    A a1;
}
 
void fun5(void)
{
    fun6();
    B b2;
}
 
void fun4(void)
{
    fun5();
    C c1;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    wcout.imbue(locale(".866"));
    wcin.imbue(locale(".866"));
 
    if (!setjmp(xen)) {
        fun1();
    }
    else {
        std::cout << "Exception!\n";
    }
 
    try{
        fun4();
    }
 
    catch(...)
    {
        wcout << L"С конструкторами!\n\n";
    }
 
    return 0;
}
сделал как вы сказали, 3 функции для прыжка и три для throw, но не могу понять почему throw работает странно, вот что выдает:

C++
1
2
3
4
5
6
Exception!
Конструктор А
Деструктор А
С конструкторами!
 
Деструктор А                                <----- Откуда это берется?
Заранее спасибо за помощь!
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
04.02.2013, 01:13     setjump/longjump #7
Да удивление вызывает вон тот деструктор в четвёртой строке, а не в седьмой. Седьмая — это дополнение к конструктору из третьей строки. Это конструкторы-деструкторы того A, который выбрасывается throw в 74 строке исходника. А вот что это в четвёртой строке не знаю, потому что у меня такого не происходит.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11817 / 6796 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
04.02.2013, 01:46     setjump/longjump #8
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
потому что у меня такого не происходит.
На студии происходит
Однако, если добавить
C++
1
A(A & x) {wcout << L"Конструктор копирования А\n";}
в класс, то такого не происходит, однако сам конструктор копирования не вызывается(во всяком случае на консоль строка "конструктор копирования A" не выводится)
yoghurt92
373 / 344 / 22
Регистрация: 17.05.2012
Сообщений: 1,049
04.02.2013, 12:01  [ТС]     setjump/longjump #9
Croessmah, так а с чем же тогда это связано?
Yandex
Объявления
04.02.2013, 12:01     setjump/longjump
Ответ Создать тему
Опции темы

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