Интерференция goto и объявления экземпляра класса

Модератор: Модераторы разделов

Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

Компилялятор gcc (g++) выдает ошибку если goto обходит объявление класса, что за новые ворота? Что делать? Не Паскаль однако finalize нет. Или есть?
par у меня структура куда разбираются параметры командной строки, работает
sv мой класс, соответственно в коде неявный вызов конструктора, без goto работает.
goto без объявления класса работает

Код: Выделить всё

int main(int argc, char** argv)
{
parameters par;
if(update_par(argc, argv, par))
   {
   ret = -1;
   goto finish;
   }

sv svrtk1(par.n, par.rmax);

finish:
return  ret;
}


Код: Выделить всё

oz.cc: In function ‘int main(int, char**)’:
oz.cc:141: error: jump to label ‘finish’
oz.cc:136: error:   from here
oz.cc:139: error:   crosses initialization of ‘sv svrtk1’


Дочитал до этого места! Компилятор не допускает обхода конструктора. Тем не менее что делать чтобы сделать блок завершения программы в одном месте?
Спасибо сказали:
Аватара пользователя
Voice
Сообщения: 1073
Статус: столлманист
ОС: Debian GNU/Linux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Voice »

Код: Выделить всё

sv svrtk1(par.n, par.rmax);

Это что такое? Зачем там пробел?,

// Ой. Извиняюсь. Понял. :blush:
"И может собственных Платонов и быстрых разумом Невтонов российская земля рождать."
М. В. Ломоносов
Спасибо сказали:
Аватара пользователя
Hater
Сообщения: 165
ОС: Archlinux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Hater »

kt315e писал(а):
11.08.2008 10:40
Тем не менее что делать чтобы сделать блок завершения программы в одном месте?

Функция? Вообще в данном случае вместо goto можно спокойно return поставить. Но я так понял, что goto будет переправлять к набору операторов.
kt315e писал(а):
11.08.2008 10:40
int main(int argc, char** argv)
{
parameters par;
if(update_par(argc, argv, par))
{
ret = -1;
goto finish;
}

sv svrtk1(par.n, par.rmax);

finish:
return ret;
}

Так не пойдёт

Код: Выделить всё

int main(int argc, char** argv)
{
parameters par;
if(update_par(argc, argv, par))
{
ret = -1;
/*код, нахолящийся после метки в 1-м варианте*/
}
else
{
/*......*/
sv svrtk1(par.n, par.rmax);
/*......*/
}
}

?
last.fm user Hater-X
Спасибо сказали:
Аватара пользователя
Hater
Сообщения: 165
ОС: Archlinux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Hater »

Hater писал(а):
11.08.2008 11:19
Так не пойдёт
Код
int main(int argc, char** argv)
{
parameters par;
if(update_par(argc, argv, par))
{
ret = -1;
/*код, нахолящийся после метки в 1-м варианте*/
}
else
{
/*......*/
sv svrtk1(par.n, par.rmax);
/*......*/
}
}

?

Бред написал.
Ну пока мы не увидим весь код, сложно что-либо предложить.
last.fm user Hater-X
Спасибо сказали:
MiK13
Сообщения: 1289
ОС: Linux Debian

Re: Интерференция goto и объявления экземпляра класса

Сообщение MiK13 »

Я очень плохо знаю C++, но подозреваю, что в данном случае ошибка происходит из-за того, что в строке 139 (sv svrtk1(par.n, par.rmax);) происходит создание объекта, который уничтожается в конце функции. goto обходит создание объекта и получается что в конце надо уничтожить объект, который не создан.
Предполагаю, что в данном случае можно строку 139 заключить в фигурные скобки.
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

HATER:
Так в том и дело что я хочу поставить код завершения программы в одном месте, а не множить его в каждом if проверяющем на вшивость. Если компилятор следит за конструкторами придется все конструкторы ставить в начале программы, а фактическую инициализацию проводить после того как станут известны необходимые параметры. Тогда деструктор корявый получится, должен знать в каком состоянии объект находится, выделял я память для внутренних переменных или нет.
Спасибо сказали:
Аватара пользователя
Hater
Сообщения: 165
ОС: Archlinux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Hater »

kt315e писал(а):
11.08.2008 11:34
HATER:
Так в том и дело что я хочу поставить код завершения программы в одном месте, а не множить его в каждом if проверяющем на вшивость. Если компилятор следит за конструкторами придется все конструкторы ставить в начале программы, а фактическую инициализацию проводить после того как станут известны необходимые параметры. Тогда деструктор корявый получится, должен знать в каком состоянии объект находится, выделял я память для внутренних переменных или нет.

Не понял. Т.е. кроме return ret; после метки ничего не будет? Я правильно понял?
last.fm user Hater-X
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

MiK13 писал(а):
11.08.2008 11:32
Я очень плохо знаю C++, но подозреваю, что в данном случае ошибка происходит из-за того, что в строке 139 (sv svrtk1(par.n, par.rmax);) происходит создание объекта, который уничтожается в конце функции. goto обходит создание объекта и получается что в конце надо уничтожить объект, который не создан.
Предполагаю, что в данном случае можно строку 139 заключить в фигурные скобки.

Ошибка исчезнет, заодно после выхода из фигурных скобок объект выйдет из области видимости и самоликвидируется.

Hater писал(а):
11.08.2008 11:42
kt315e писал(а):
11.08.2008 11:34
HATER:
Так в том и дело что я хочу поставить код завершения программы в одном месте, а не множить его в каждом if проверяющем на вшивость. Если компилятор следит за конструкторами придется все конструкторы ставить в начале программы, а фактическую инициализацию проводить после того как станут известны необходимые параметры. Тогда деструктор корявый получится, должен знать в каком состоянии объект находится, выделял я память для внутренних переменных или нет.

Не понял. Т.е. кроме return ret; после метки ничего не будет? Я правильно понял?


Конечно нет, будет много кода. Который и не хочу плодить по разным местам. Здесь приведена только схема.
Спасибо сказали:
MiK13
Сообщения: 1289
ОС: Linux Debian

Re: Интерференция goto и объявления экземпляра класса

Сообщение MiK13 »

kt315e писал(а):
11.08.2008 11:34
HATER:
Так в том и дело что я хочу поставить код завершения программы в одном месте, а не множить его в каждом if проверяющем на вшивость. Если компилятор следит за конструкторами придется все конструкторы ставить в начале программы, а фактическую инициализацию проводить после того как станут известны необходимые параметры. Тогда деструктор корявый получится, должен знать в каком состоянии объект находится, выделял я память для внутренних переменных или нет.

Думаю, что проблема не в деструкторе, а в самом объекте. В конце блока компилятор перед ставит код удаления всех объектов, созданных в данном блоке. А код создания объекта -- в месте его объявления.
В данном случае получается, что надо уничтожить объект, который, возможно, и не было создан.
A

Код: Выделить всё

 {
  sv svrtk1(par.n, par.rmax);
}
не помогает?
Спасибо сказали:
Аватара пользователя
Hater
Сообщения: 165
ОС: Archlinux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Hater »

kt315e
Есть ли возможность этот код выделить в отдельную функцию?
last.fm user Hater-X
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

MiK13 писал(а):
11.08.2008 11:51
kt315e писал(а):
11.08.2008 11:34
HATER:
Так в том и дело что я хочу поставить код завершения программы в одном месте, а не множить его в каждом if проверяющем на вшивость. Если компилятор следит за конструкторами придется все конструкторы ставить в начале программы, а фактическую инициализацию проводить после того как станут известны необходимые параметры. Тогда деструктор корявый получится, должен знать в каком состоянии объект находится, выделял я память для внутренних переменных или нет.

Думаю, что проблема не в деструкторе, а в самом объекте. В конце блока компилятор перед ставит код удаления всех объектов, созданных в данном блоке. А код создания объекта -- в месте его объявления.
В данном случае получается, что надо уничтожить объект, который, возможно, и не было создан.
A

Код: Выделить всё

 {
  sv svrtk1(par.n, par.rmax);
}
не помогает?

Ты гений, однако. Помещу весь код где используется объект в фигурные скобки. Как то оно не по С/C++ -шному выглядит только, LISPовщина какая то.
Спасибо сказали:
Аватара пользователя
Hater
Сообщения: 165
ОС: Archlinux

Re: Интерференция goto и объявления экземпляра класса

Сообщение Hater »

MiK13 писал(а):
11.08.2008 11:51
A
Код
{
sv svrtk1(par.n, par.rmax);
}
не помогает?


kt315e писал(а):
11.08.2008 11:50
Ошибка исчезнет, заодно после выхода из фигурных скобок объект выйдет из области видимости и самоликвидируется.
last.fm user Hater-X
Спасибо сказали:
MiK13
Сообщения: 1289
ОС: Linux Debian

Re: Интерференция goto и объявления экземпляра класса

Сообщение MiK13 »

kt315e писал(а):
11.08.2008 11:50
Ошибка исчезнет, заодно после выхода из фигурных скобок объект выйдет из области видимости и самоликвидируется.

Я что-то не понял: это способ решения проблемы или подтверждение её решения?
P.S. Этот пост я прочитал, когда уже написал свой предыдущий. И данный вопрос не возник бы, если бы автор был не kt315e
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

Hater писал(а):
11.08.2008 11:55
kt315e
Есть ли возможность этот код выделить в отдельную функцию?

Нет эта функция не будет видеть всех переменных из main, придется громоздкий костыль делать, сделаю как Mik13 советует.
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

MiK13 писал(а):
11.08.2008 11:56
kt315e писал(а):
11.08.2008 11:50
Ошибка исчезнет, заодно после выхода из фигурных скобок объект выйдет из области видимости и самоликвидируется.

Я что-то не понял: это способ решения проблемы или подтверждение её решения?
P.S. Этот пост я прочитал, когда уже написал свой предыдущий. И данный вопрос не возник бы, если бы автор был не kt315e

Смотри пост #11. Надо включить весь код использующий объект в фигурные скобки. Спасибо помогло.
Спасибо сказали:
Аватара пользователя
amaora
Сообщения: 95
ОС: Slackware

Re: Интерференция goto и объявления экземпляра класса

Сообщение amaora »

kt315e
В С++ для обработки ошибок есть исключения, goto это как то С-стиль.
кто здесь?
Спасибо сказали:
MiK13
Сообщения: 1289
ОС: Linux Debian

Re: Интерференция goto и объявления экземпляра класса

Сообщение MiK13 »

kt315e писал(а):
11.08.2008 11:56
Ты гений, однако. Помещу весь код где используется объект в фигурные скобки. Как то оно не по С/C++ -шному выглядит только, LISPовщина какая то.

(Пушкин А.С.) писал(а):И опыт -- сын ошибок трудных...

По работе "переводил" прогу с борландовского билдера на GCC (точнее, G++)
Заодно подправлял "вид" текста -- выравнивал комментарии, подравнивал блоки.
Натолкнулся: в switch после case группа операторов стоит в фигурных скобрак. Думаю: зачем? Это в Паскале надо их заключать в begin ... end. а тут зачем? Убираю скобки -- компилятор ругается (очень похожая ошибка). Думаю: в чём дело? Смотрю -- оказывается там объявление переменной (по-моему, структуры или класса). И понимаю: если скобки не поставить, то эта переменная будет удаляться в конце, а она может быть не создана, если не управление не попадёт на данный case. Восстановил скобки -- стало нормально компилироваться
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

amaora писал(а):
11.08.2008 12:08
kt315e
В С++ для обработки ошибок есть исключения, goto это как то С-стиль.

Так компилятор ругаться все равно будет на обход конструктора? А если не будет то сможет ли он понять надо или нет вызывать деструктор при выходе из области видимости?
Спасибо сказали:
svas
Сообщения: 203

Re: Интерференция goto и объявления экземпляра класса

Сообщение svas »

с++ строго следит за инициализацией объектов. В месте объявления переменной вызывается конструктор. Ошибка в том, что при выполнении программы svrtk1 может быть не инициализирован, обойти вызов конструктора. Так нельзя. :)
Можно так сделать

Код: Выделить всё

int main(int argc, char** argv)
{
parameters par;
sv *svrtk1
if(update_par(argc, argv, par))
   {
   ret = -1;
   goto finish;
   }

svrtk1 = new sv(par.n, par.rmax);
...........
delete svrtk1;

finish:
return  ret;
}
Спасибо сказали:
Аватара пользователя
amaora
Сообщения: 95
ОС: Slackware

Re: Интерференция goto и объявления экземпляра класса

Сообщение amaora »

Код: Выделить всё

#include <iostream>

class err {
public:
    int ret;
    err( int _ret ) { ret = _ret; std::cout << "+ err\n"; }
    ~err() { std::cout << "~ err\n"; }
};

class sv {
    int a;
public:
    sv( int _a ) {
        std::cout << "+ sv\n";
        if ( _a == 3 )
            throw err( -2 );
        a = _a;
    }
    ~sv() { std::cout << "~ sv\n"; }
    int get_a() const { return a; };
};

void foo( int a, int b ) /*throw ( err )*/
{
    if ( a != b )
        throw err( -1 );
}

int main(int argc, char** argv)
{
    int par = 1;

    try {
        sv sv2( argc );
        foo( par, argc );

        sv svrtk1( par );
        std::cout << "work : " << svrtk1.get_a() << " : " << sv2.get_a() << "\n";
    }
    catch ( err & er ) {
        std::cout << "erorr : " << er.ret << "\n";
        return er.ret;
    }
}


Код: Выделить всё

$ gcc -Wall -o test test.cpp -lstdc++
$ ./test
+ sv
+ sv
work : 1 : 1
~ sv
~ sv
$ ./test 1
+ sv
+ err
~ sv
erorr : -1
~ err
$ ./test 1 1
+ sv
+ err
erorr : -2
~ err


для подробностей, надо читать Бъерна, или стандарт или ... все остальное.
кто здесь?
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Интерференция goto и объявления экземпляра класса

Сообщение RasenHerz »

выход один - не городить что попало. если что-то сразу не работает значит надо пересмотреть код, то что придумал автор - не годится.

P.S. советую рыть в сторону C-шных setjmp, longjump (или что-то вроде этого - точно не помню =), рой в Гугле ). им побарабану вродь через сколько конструкторов ты прыгаешь(в С их вообще нет))). как альтернативу можно использовать встроенный ассемблер - но это не UNIX-Way и уж тем более, не C++-Way =)

P.P.S Заядлый C-шник =)))
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

Приведу для определенности мотивацию применения C++.
Прежде всего это необходимость иниациализации и соответственно ликвидации инициализированного. Хочется как можно больше сделать автоматически, чтобы не утечек памяти и код не замусоривался. Отсуда и желание использовать автоматический вызов конструкторов и деструкторов. В C получилилось громоздко, собственно кода не видно, а писать только начал. Вводить исключения не хочется по тем же причинам - рост объёма нефункционального кода.
Использование new, delete - по существу как в C malloc, free - ответственность перекладывается на программиста. Есть еще умные указатели но про них я почти ничего не знаю, есть ли они в gcc, и введены ли в стандарт? Как ими пользуются?
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Интерференция goto и объявления экземпляра класса

Сообщение RasenHerz »

это понятно. просто вы используете стиль, который близок к С, а не к С++!
собственно по сабжу:

в программах скомпилированных с помощью gcc есть специальная таблица .dtors и .ctors. Интересны они прежде всего тем, что содержат функции для деструкторов и конструкторов соответственно, т.е. функции конструкторов выполняются перед main(), а деструкторов - непосредственно перед выходом из нее с помощью системного вызова exit(). Вот небольшой пример:

Код: Выделить всё

#include <stdio.h>

static struct sv *svrtk1;
static void clean_up(void) __atribute__((destructor));

int main(int argc, char *argv[]){
   blah();
   blah();
   ..........
   blah();
   svrtk1 = (struct sv*)malloc(sizeof(struct sv));
   if(!svrtk1)
       blah();
   ..........
   exit(ret);
}

static void clean_up(void){
     if(svrtk1)
        free(svrtk1);
}

Думаю смысел понятен =).
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

RasenHerz:
Это хорошо. Только будет ли работать под другими компиляторами? И ликвидировать так можно только глобальные объекты.
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Интерференция goto и объявления экземпляра класса

Сообщение RasenHerz »

Под ваш код мой пример подходит идеально.
И ликвидировать так можно только глобальные объекты.

Можно создать связный список объектов нуждающихся в удалении и в деструкторе его очистить. но все это сложные пути =) так что не мудрите - если проскакиваете всего один конструктор, то можно воспользоваться и глобальной переменной.
Только будет ли работать под другими компиляторами?

по-моему вы ясно сказали что используете gcc.
все это костыли, вам НЕОБХОДИМО переписать код.
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

RasenHerz писал(а):
11.08.2008 18:23
все это костыли, вам НЕОБХОДИМО переписать код.

Я использовал решение Mik13. Для данного случая оно тоже очень хорошо подходит. Сначала получаем параметры, потом используя их инициализируем объекты во вложенной области видимости. Это соответствует структуре данной программы поэтому не костыль. Но в общем случае может не сработать. Хочется общего решения для ликвидации локальных объектов.
Сработает ли такое:
объявляем указатели на объекты, инициализируя их NULL, вызываем new для создания объекта, или не вызываем (по какой веточке пойдет). Перед выходом из области видимости ликвидируем все объекты указатель на которые не равен нулю?
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

Похоже нашел:
"Также уничтожаются все локальные объекты созданные к моменту запуска исключения"
Философия С++. Б. Эккель, Ч. Эллисон.

Только не понял созданные c помощью new понимаются как локальные или нет?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5456
ОС: Gentoo

Re: Интерференция goto и объявления экземпляра класса

Сообщение /dev/random »

kt315e писал(а):
11.08.2008 21:18
Похоже нашел:
"Также уничтожаются все локальные объекты созданные к моменту запуска исключения"
Философия С++. Б. Эккель, Ч. Эллисон.

Только не понял созданные c помощью new понимаются как локальные или нет?

Нет.
Спасибо сказали:
Аватара пользователя
kt315e
Сообщения: 318
ОС: Debian 11

Re: Интерференция goto и объявления экземпляра класса

Сообщение kt315e »

Большое спасибо всем!!!
Читаю книжки :) Теперь понятней!
Спасибо сказали: