реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> __no_init и конструктор в С++
jorikdima
сообщение Jan 19 2011, 21:00
Сообщение #1


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Приветствую.
Есть некий класс, который содержит в качестве полей большие массивы. Кроме того, есть и другие поля, которые надо инициализировать и есть рукописный конструктор, который готов провести эту инициализацию. Так как массивы инитить необязательно, то есть большое желание сократить код прошивки путем отказа от дефолтовой инициализации этих больших буферов (прошивка сокращается на объем равный размеру буферов, так как инициализирующий массив, который переписывается в РАМ в стартапе попросту отсутствует). Я обнадежился, надеясь добавить __no_init в описание поля класса, но конечно не прокатило, так как эта директива касается только объектов целиком. Тогда я объявил весь объект (глобальный) моего класса __no_init, а инициализацию нужных мне полей добавил явно в коструктор, прошивка сократилась, но конструктор не вызывается. Почему отсутствие инициализации всех полей класса приводит и к отказу вызывать конструктор (просто функция по сути)? Можно как-то выкрутиться из ситуации? А то очень уж хочется ничего не делая сократить прошивку на четверть.
Спасибо.
Go to the top of the page
 
+Quote Post
Artem_Petrik
сообщение Jan 19 2011, 23:11
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 443
Регистрация: 22-07-06
Из: Украина, г. Харьков
Пользователь №: 19 006



Раз оно так много места занимает, то, наверно, в проекте имеется только один экземпляр класса? Тогда можно буфера сделать static-ами, и тогда, их можно будет сделать __no_init без проблем.

ЗЫ еще, если все поля класса объявить без инициализации, а нужные значения присвоить в конструкторе, то, по умолчанию, все будет иинициализировано нулями, и вся структура должна попасть в сегмент, инициализируемый нулями в стартапе циклом (типа сегмент NEAR_Z или zeroinit section)
Go to the top of the page
 
+Quote Post
Aprox
сообщение Jan 20 2011, 06:38
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131



jorikdima
Может, убрать __no_init маcсивы из состава класса, сделать их глобальными, а конструктору этого класса передавать только указатель на массив?

Go to the top of the page
 
+Quote Post
dxp
сообщение Jan 20 2011, 06:51
Сообщение #4


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(jorikdima @ Jan 20 2011, 03:00) *
Приветствую.
Есть некий класс, который содержит в качестве полей большие массивы. Кроме того, есть и другие поля, которые надо инициализировать и есть рукописный конструктор, который готов провести эту инициализацию. Так как массивы инитить необязательно, то есть большое желание сократить код прошивки путем отказа от дефолтовой инициализации этих больших буферов (прошивка сокращается на объем равный размеру буферов, так как инициализирующий массив, который переписывается в РАМ в стартапе попросту отсутствует).

Что-то я не понял, откуда оверхед. Если есть конструктор, то в нем программист явно указывает, что из представления класса инициализировать и как. Если инициализация массивов не нужна, так и не описывать ее, этот член просто не будет проинициализирован. Насколько я ничего не помню, как-то так.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jan 20 2011, 08:09
Сообщение #5


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Цитата(dxp @ Jan 20 2011, 09:51) *
Что-то я не понял, откуда оверхед. Если есть конструктор, то в нем программист явно указывает, что из представления класса инициализировать и как. Если инициализация массивов не нужна, так и не описывать ее, этот член просто не будет проинициализирован. Насколько я ничего не помню, как-то так.

Чего-то я до конца не понимаю. Для начала несколько цитат из Страуструппа:
1. Глава 10.2.3 Конструкторы
Цитата
Если класс имеет конструктор, все объекты этого класса будут проинициализированны.

2. Глава 10.4.2 Конструкторы по умолчанию
Цитата
Конструктор по умолчанию, сгенерированный компилятором, неявно вызывает конструкторы по умолчанию для членов класса и конструкторы базовых классов. Например:
Код
struct
{
    int i;
    int vi[10];
    Table t1;
    Table vt[10];
};
Tables tt;

В этом примере переменная tt будет проинициализированна сгенерированным конструктором по умолчанию, который вызовет Table(15) (прим. Для класса Table определен конструктор с дефолтовым аргументом 15) для tt.t1 и каждого элемента tt.vt. С другой стороны, tt.i и элементы tt.vi не проинициализированны, потому что их тип не является классом. Причина различной обработки классов и встроенных типов заключается в требовании совместимости с С и в боязни вызвать дополнительные затраты времени на этапе выполнения.


Что на деле. Я запустил MS Visual Studio и нарисовал там простой код:
Код
class JJ
    {
    private:
        int y;
        int e[3];

    public:
        JJ()
            {

            }
    };


JJ j1;
void main()
    {
    JJ j2;
    while(1);
    }


Создается два объекта, один на стеке, один глобальный. Определен пустой конструктор по умолчанию, хотя это не играет никакой роли! В результате объект j1 полностью инитится нулями, а j2 не инитится.
Почему для j2 игнорируется цитата 1, а для j1 цитата два?
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Jan 20 2011, 08:25
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(jorikdima @ Jan 20 2011, 14:09) *
Чего-то я до конца не понимаю. Для начала несколько цитат из Страуструппа:
Почему для j2 игнорируется цитата 1, а для j1 цитата два?


Встроенные типы НЕ имеют конструкторов по умолчанию.
j1 скорее всего располагается в "zero-initialized" области
Go to the top of the page
 
+Quote Post
dxp
сообщение Jan 21 2011, 02:56
Сообщение #7


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(Dima_G @ Jan 20 2011, 14:25) *
Встроенные типы НЕ имеют конструкторов по умолчанию.
j1 скорее всего располагается в "zero-initialized" области

+1.

jorikdima
Конкретный компилятор разместил объект в обнуленной области памяти. А другой компилятор может этого не сделать. Поэтому рассчитывать на это нельзя. Вам же важно, чтобы не было оверхеда на инициализацию массива. Его и нет. Разве не так?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jan 21 2011, 06:13
Сообщение #8


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Цитата(dxp @ Jan 21 2011, 05:56) *
Вам же важно, чтобы не было оверхеда на инициализацию массива. Его и нет. Разве не так?

Не так, видимо. Ибо разница в объеме кода, занимаемое ПО с __no_init и без различается на 5388 - 4146 = около 1K. Пусть даже __no_init убирает конструкторы (почему???), они у меня очень маленькие.
Пока я не смотрел откуда отрезается кусок кода, что за функция, стартап или что. Смогу только вечером, тогда и напишу продолжение. Спасибо.
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Jan 21 2011, 06:26
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(dxp @ Jan 21 2011, 08:56) *
+1.

jorikdima
Конкретный компилятор разместил объект в обнуленной области памяти. А другой компилятор может этого не сделать.


ЕМНИП, глобальные объекты всегда инициализируются нулем, если их конструктор не изменит значение объекта.
Точнее - глобальные объекты всегда создаются в инициализированной нулем области памяти


Цитата(jorikdima @ Jan 21 2011, 12:13) *
Пока я не смотрел откуда отрезается кусок кода, что за функция, стартап или что.

Ставлю на стартап, инициализацию "zero-initialized" области rolleyes.gif
Go to the top of the page
 
+Quote Post
dxp
сообщение Jan 21 2011, 09:27
Сообщение #10


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(jorikdima @ Jan 21 2011, 12:13) *
Не так, видимо. Ибо разница в объеме кода, занимаемое ПО с __no_init и без различается на 5388 - 4146 = около 1K. Пусть даже __no_init убирает конструкторы (почему???), они у меня очень маленькие.

__no_init - это другая тема. Если есть возможность, пройдите отладчиком через конструктор - увидите, что он конкретно делает. Уверен, никакой инициализации массивов он не производит.

А __no_init, подозреваю, просто делает так, что конструктор объекта не вызывается вообще. Т.е. отсутствует и само тело конструктора, и его вызов из ctor_loop. Посмотрите кодогенерацию конструктора, нет ли там матершинных слов типа ??_operator_new (или чего-то в этом роде). Если есть, то это объясняет такой прирост размера.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jan 21 2011, 21:07
Сообщение #11


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Век живи, век учись sm.gif
А дело было так:
Я пишу на С++ и нередко пользуюсь виртуальными функциями, в данном проекте так же. Как устроена работа с виртуальными функциями можно прочитать тут. Так вот, как выясняется (в доке на компайлер про это ни слова) __no_init, судя по всему, для объектов пользовательских классов исключает вызов конструктора. То есть для массивов или других глобальных объектов обычных типов он просто не помещает их в секцию инициализируемых данных, а для пользовательских классов не вызывает конструктор. Это догадка, как я сказал в доке ни слова.
Классы, объекты которого я сделал __no_init , содержат виртуальные методы. Конструктор для этих объектов не вызывается! А это значит, что таблица виртуальных методов не заполняется и адреса моих виртуальных функций туда не попадают. Далее линкер видит, что переопределенные мои виртуальные функции никем не используются (конструктора то нету, помещающие их адреса в таблицу) и благополучно их выкидывает! Вот и минус 1к кода (код функций). Я был сбит с пути тем, что объем высвобождаемой памяти примерно равен размеру буферов в объектах, которые я пометил __no_init - это просто совпадение.
Всем спасибо.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 14:50
Рейтинг@Mail.ru


Страница сгенерированна за 0.0147 секунд с 7
ELECTRONIX ©2004-2016