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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.94
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
#1

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

19.03.2010, 23:04. Просмотров 2013. Ответов 10
Метки нет (Все метки)

Есть некий класс,и в нем в секции 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.
Хотя бы теоретически,отчего такое может быть? Есть ли какие-то ограничения при работе с контейнерами,указателями и памятью на порядок переменных в интерфейсе класса?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.03.2010, 23:04
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Странный SIGSEGV, или что зависит от порядка написания интерфейса класса (C++):

Невозможно создать экземпляр абстрактного класса или интерфейса - C#
using System.Windows.Media.Imaging; using System.Drawing; Есть эти две библиотеки, нужно создать ,ругается на подчеркнутый image ...

Странный баг или я что то не понимаю - C#
Добрый вечер / день. Столкнулся в непонятным, только с утра всё отлично компилировало код. Просто пишет : " не существует в конкретном...

Что лучьше для написания WEB-страниц под JBoss, JSP или Java? - Java EE
Мне необходимо создать несколько разделов для сайта на движке Liferay (Liferay.com) который стоит на связке SDK_4.2.0+JBoss+Tomcat ...

Недопустимая лексема "=" в объявлении класса, структуры или интерфейса - C#
public bool FirstRun { get; set; } = true; public List<ManifestEntry> Entries { get; set; } ...

Недопустимая лексема "for" в объявлении класса, структуры или интерфейса - C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using...

Ошибка: недопустимый токен "using" в объявлении класса, структуры или интерфейса - C#
using System.Windows.Forms; class SimpleWindowsFormWithButton: Form { Button button1; public SimpleWindowsFormWithButton() ...

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

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

Добавлено через 28 минут
Лирическое отступление. При передаче string'а (да и любого другого класса) в качестве read-only параметра вместо "const string name" используй "const string &name" (передачу по косвенности). В этом случае не будет дублирования экземпляра класса, как это происходит при передаче по значению.
1
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.03.2010, 20:21  [ТС] #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
  {
 
  }
0
Evg
Эксперт CАвтор FAQ
17815 / 6025 / 388
Регистрация: 30.03.2009
Сообщений: 16,554
Записей в блоге: 26
20.03.2010, 20:27 #6
Долго смотрел на это хозяйство. Из интересного увидел только то, что класс содержит поле типа Type, для которого конструктор явно не вызывается, а потому оно должно инициализироваться конструктором по умолчанию. А можешь нарезать короткий пример, на котором ещё сохраняется указанный warning?
1
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.03.2010, 23:06  [ТС] #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)
0
Evg
Эксперт CАвтор FAQ
17815 / 6025 / 388
Регистрация: 30.03.2009
Сообщений: 16,554
Записей в блоге: 26
21.03.2010, 09:31 #8
Вот я и надеялся увидеть union'ы в исходниках... Ладно, если не забуду - попробую на работе ревизию выдрать
1
Evg
Эксперт CАвтор FAQ
17815 / 6025 / 388
Регистрация: 30.03.2009
Сообщений: 16,554
Записей в блоге: 26
22.03.2010, 14:39 #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'а понятна, но это НЕ объясняет выпадение в кору. Там какая-то другая причина
1
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
22.03.2010, 21:53  [ТС] #10
>но это НЕ объясняет выпадение в кору
В каком смысле в кору? Я так понял,это один единственный,многострочный warning,который надо читать одним предложением. Или ты о чём-то другом толкуешь?

А,понял,ты про segfault... да,скорее всего,это как раз из за unions:там идёт где-то запрос на уже затёртый указатель(в свете твоего объяснения выше)
0
Evg
Эксперт CАвтор FAQ
17815 / 6025 / 388
Регистрация: 30.03.2009
Сообщений: 16,554
Записей в блоге: 26
22.03.2010, 21:59 #11
Цитата Сообщение от #pragma Посмотреть сообщение
то программа вылетает с Segmentation fault
В этом случае в старых системах по умолчанию сбрасывался файл core - образ памяти и регистров процесса на момент смерти. В новых системах по умолчанию сие отключено (включается через "ulimit -c unlimited"). Поэтому такое фатальное завершение на слэнге называют "процесс выпал в кору"

Поэтому такой warning не объясняет причин того, почему при перестановке полей в классе у тебя программа перестаёт работать, потому как причина, по которой выдаётся предупреждение, лежит скорее в области теоретической опасности, нежили практической.
2
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.03.2010, 21:59
Привет! Вот еще темы с ответами:

Ошибка 7 Недопустимая лексема "(" в объявлении класса, структуры или интерфейса - C#
using System; using System.Text; namespace PropertiesExample3 { //обьявление класса программы class Programm { ...

Невозможно создать экземпляр абстрактного класса или интерфейса "System.IO.TextWriter" - C#
SaveFileDialog saveFileDialog1 = new SaveFileDialog(); if (saveFileDialog1.ShowDialog() == DialogResult.OK) { ...

Какой js-фреймворк взять для написания админского интерфейса портала - JavaScript
В общем, мучаюсь вопросом: какой js-фреймворк взять для написания админского интерфейса портала. Портал достаточно сложный, обладающий...

Функции в JavaScript являются объектами первого класса, функциями высшего порядка или и тем и другим одновременно? - JavaScript
читаю пару книг и немного запутался... вопрос следующий: функции в JavaScript являются объектами первого класса, функциями высшего...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
22.03.2010, 21:59
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru