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

Странный SIGSEGV, или что зависит от порядка написания интерфейса класса - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.94
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
19.03.2010, 23:04     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #1
Есть некий класс,и в нем в секции private записано следующее:
C++
1
2
3
4
5
6
7
8
       private:
           Value *val;
           Types var_type;
           bool is_initialized;
           bool is_shared;
           string var_name;
           var_Arr_t *page; // In which page variable located.
       public:
Я не знаю,важно ли это,но в конструкторах это:
конструкторы
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  Variable::Variable (const string name):val(NULL)
  {
     var_name = name;
     is_initialized = false;// The default
     is_shared      = false;// The default
  }
/* -------------------------------------------------------------------------- */
  Variable::Variable (const string name,Types type):val(NULL)
  {
     var_name = name;
     var_type = type;
     is_initialized = false;// The default
     is_shared      = false;// The default
  }
/* -------------------------------------------------------------------------- */
  Variable::Variable (const string name,Value *value)
  {
     var_name = name;
     val = value;
     is_initialized = false;// The default
     is_shared      = false;// The default
  }

И всё работает. Но если поменять так:
C++
1
2
3
4
5
6
7
8
       private:
           Value *val;
           bool is_initialized;
           bool is_shared;
           string var_name;
           Types var_type;
           var_Arr_t *page; // In which page variable located.
       public:
,то есть просто передвинуть переменную enum Types var_type; немного вниз,больше ничего не трогая,и перекомпилировать прогу,а потом запустить,то программа вылетает с Segmentation fault.
Для справки скажу,что я обнаружил это странное поведение,когда пытался сделать конструкторы со значениями по умолчанию так:
C++
1
2
3
4
5
6
7
/* -------------------------------------------------------------------------- */
  Variable::Variable (const string name):val(NULL),var_name(name),
     is_initialized(false),// The default
     is_shared(false)// The default
  {
 
  }
на что получил странные предупреждения от gcc:
Код
/home/user/Interpreter/Interpreter/intermediate/variable.h||In constructor ‘Variable::Variable(std::string)’:|
/home/user/Interpreter/Interpreter/intermediate/variable.h|52|warning: ‘Variable::var_name’ will be initialized after|
/home/user/Interpreter/Interpreter/intermediate/variable.h|50|warning:   ‘bool Variable::is_initialized’|
/home/user/Interpreter/Interpreter/intermediate/variable.cpp|42|warning:   when initialized here|
||=== Build finished: 0 errors, 3 warnings ===|
- поменял в интерфейсе их местами - предупреждения пропали. Потом передвинул enum Types var_type; - появился Segfault.
Хотя бы теоретически,отчего такое может быть? Есть ли какие-то ограничения при работе с контейнерами,указателями и памятью на порядок переменных в интерфейсе класса?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.03.2010, 23:04     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса
Посмотрите здесь:

Отделение интерфейса класса от реализации C++
Странный синтаксис конструктора класса C++
К знатокам С++: это самодостаточный язык, или всё таки он зависит от Си C++
C++ Отделение интерфейса класса от его реализации
Объяснить от чего зависит размер указателя и что такое арифметика указателей C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Genius Ignat
1233 / 771 / 44
Регистрация: 16.09.2009
Сообщений: 2,014
19.03.2010, 23:09     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #2
Странно у меня таких ошибок не возникало, что я только с конструкторами
и классами не вытворял такого не видал.
Может компилятор такой.
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.03.2010, 00:19  [ТС]     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #3
Спросил на IRC, ответ был такой
Код
Q.: - Моя программа вылетает при попытке поменять местами переменные в интефейсе класса
      Этот порядок может быть важен и при каких-то условиях?
A.: Да,переменные инициализируются перед вызовом конструктора в порядке
      их следования,например,в интерфейсе класса. Для POD структур порядок 
      меняет разметку памяти,так что это тоже может влиять на подобные ошибки
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
20.03.2010, 13:03     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #4
В тексте выдачи компилятора у тебя указана строки 52, 50. А в пересчёте на твой пример это что будет?

Добавлено через 41 секунду
И "variable.cpp|42" к чему относится

Добавлено через 28 минут
Лирическое отступление. При передаче string'а (да и любого другого класса) в качестве read-only параметра вместо "const string name" используй "const string &name" (передачу по косвенности). В этом случае не будет дублирования экземпляра класса, как это происходит при передаче по значению.
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.03.2010, 20:21  [ТС]     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #5
Цитата Сообщение от Evg Посмотреть сообщение
В тексте выдачи компилятора у тебя указана строки 52, 50. А в пересчёте на твой пример это что будет?
Добавлено через 41 секунду
И "variable.cpp|42" к чему относится
в пересчёте на пример будет 52 строка == 5 строка и 50 строка == 3 строка тут:
C++
1
2
3
4
5
6
7
8
       private:
           Value *val;
           bool is_initialized;
           bool is_shared;
           string var_name;
           Types var_type;
           var_Arr_t *page; // In which page variable located.
       public:
, variable.cpp|42 == 2 строке тут:
C++
1
2
3
4
5
6
7
/* -------------------------------------------------------------------------- */
  Variable::Variable (const string name):val(NULL),var_name(name),
     is_initialized(false),// The default
     is_shared(false)// The default
  {
 
  }
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
20.03.2010, 20:27     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #6
Долго смотрел на это хозяйство. Из интересного увидел только то, что класс содержит поле типа Type, для которого конструктор явно не вызывается, а потому оно должно инициализироваться конструктором по умолчанию. А можешь нарезать короткий пример, на котором ещё сохраняется указанный warning?
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.03.2010, 23:06  [ТС]     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #7
Я не думаю,что смогу повторить(почти уверен,так как не понимаю сути проблемы),и раз ты не смог повторить у себя такой warning.
В моей программе,скорее всего,это как-то связано с использованием unions в представлении(я так думаю,а в чём именно дело,не понимаю)
Но можешь стянуть ревизию 78 и применить патч:
Код
Index: Interpreter/intermediate/variable.h
===================================================================
--- Interpreter/intermediate/variable.h	(revision 78)
+++ Interpreter/intermediate/variable.h	(working copy)
@@ -47,10 +47,10 @@
    {
        private:
            Value *val;
-           string var_name;
            Types var_type;
            _bool_t is_shared;
            _bool_t is_initialized;
+           string var_name;
            var_Arr_t *page; // In which page variable located.
        public:
            Variable (){};
Добавлено через 33 минуты
Забыл указать версию компилятора:
Код
$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,
fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared
 --with-system-zlib --libexecdir=/usr/lib --without-included-gettext
 --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2
 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug
 --enable-objc-gc --enable-mpfr --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
21.03.2010, 09:31     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #8
Вот я и надеялся увидеть union'ы в исходниках... Ладно, если не забуду - попробую на работе ревизию выдрать
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
22.03.2010, 14:39     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #9
Короткий пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <string>
 
class Variable
{
  private:
#if 1
    bool is_shared;
    std::string var_name;
#else
    std::string var_name;
    bool is_shared;
#endif
 
  public:
    Variable (const std::string name);
};
 
Variable::Variable (const std::string name)
  : var_name (name),
    is_shared (false)
{
}
Код
$ g++ -c -Wall t.cc
t.cc: In constructor 'Variable::Variable(std::string)':
t.cc:8: warning: 'Variable::var_name' will be initialized after
t.cc:7: warning:   'bool Variable::is_shared'
t.cc:18: warning:   when initialized here
Если заменить "#if 1" на "#if 0", то warning'а не будет. Теперь надо думать, что сие означает

У меня проявляется на gcc-3.4.6 и gcc-4.1.2

Добавлено через 1 час 25 минут
Вот чего мне умные люди сказали:

короче, там такая фишка
если у тебя в конструкторе инициализация данных происходит строго по очереди, то даже если ты ошибся где-то, и поле налазит на какое-то другое поле, ты не перепишешь чужих данных
к примеру, если у тебя структура данных что-то вроде
{int a[5], int b[7]}
а ты записываешь в "a" вместо 5 интов, к примеру, 8, тогда, если ты инициализируешь поля:
1.b 2.a -> ты затрешь данные, которые хранятся в "b"
1.a 2.b -> у тебя b будет корректно, а в "a" будет хранится 5 интов (из 8)
Это считается правильным не только с точки зрения "контроль за собственными ошибками", но и с точки зрения взлома. К примеру, если у тебя
{char b[10], int *ddd}, злоумышленники, как-нибудь взломав код, и передав в "b" на 4 char-а больше смогут контролировать и поле "ddd"
вроде так, если я не ошибаюсь

когда они (gcc-шники) поняли, что иногда инициализация в некорректном виде может привести к проблемам, они не стали заморачиваться, а теперь выдают предупреждение при _любых_ инициализациях в не том порядке, в котором они были объявлены
т.е. не зависит от типов, хоть два bool сделай
-Wno-reorder - поможет избавиться
Сентенция вытекает такая, что причина warning'а понятна, но это НЕ объясняет выпадение в кору. Там какая-то другая причина
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
22.03.2010, 21:53  [ТС]     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #10
>но это НЕ объясняет выпадение в кору
В каком смысле в кору? Я так понял,это один единственный,многострочный warning,который надо читать одним предложением. Или ты о чём-то другом толкуешь?

А,понял,ты про segfault... да,скорее всего,это как раз из за unions:там идёт где-то запрос на уже затёртый указатель(в свете твоего объяснения выше)
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.03.2010, 21:59     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса
Еще ссылки по теме:

C++ Спрятать часть интерфейса класса
Написания класса Car C++
C++ Что лучше: расширить интерфейс класса или сделать публичным подкласс?

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

Или воспользуйтесь поиском по форуму:
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
22.03.2010, 21:59     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса #11
Цитата Сообщение от #pragma Посмотреть сообщение
то программа вылетает с Segmentation fault
В этом случае в старых системах по умолчанию сбрасывался файл core - образ памяти и регистров процесса на момент смерти. В новых системах по умолчанию сие отключено (включается через "ulimit -c unlimited"). Поэтому такое фатальное завершение на слэнге называют "процесс выпал в кору"

Поэтому такой warning не объясняет причин того, почему при перестановке полей в классе у тебя программа перестаёт работать, потому как причина, по которой выдаётся предупреждение, лежит скорее в области теоретической опасности, нежили практической.
Yandex
Объявления
22.03.2010, 21:59     Странный SIGSEGV, или что зависит от порядка написания интерфейса класса
Ответ Создать тему
Опции темы

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