Я — самоучка, так что сорри за глупые вопросы.
Вот есть у меня допустим библиотека классов. И допустим есть там (несколько) классы, у которых есть static переменные-члены. (этож фактически получается те же глобальные переменные) Ну, например класс сделанный по шаблону Monolite. Вопрос. А если я не юзаю этот монолит в своей программе, его статические переменные всеравно будут у меня место занимать или нет? Вот если бы у меня вместо этого монолита были бы только его переменные и функции в намаспейсе, то компиллер ведь все равно выделит статическое место для этих переменный, пофиг использую я их или нет. Да? А вот в случае с монолитным классом?
Здравствуйте, r2b2, Вы писали:
R>Я — самоучка, так что сорри за глупые вопросы. R>Вот есть у меня допустим библиотека классов. И допустим есть там (несколько) классы, у которых есть static переменные-члены. (этож фактически получается те же глобальные переменные) Ну, например класс сделанный по шаблону Monolite. Вопрос. А если я не юзаю этот монолит в своей программе, его статические переменные всеравно будут у меня место занимать или нет? Вот если бы у меня вместо этого монолита были бы только его переменные и функции в намаспейсе, то компиллер ведь все равно выделит статическое место для этих переменный, пофиг использую я их или нет. Да? А вот в случае с монолитным классом?
В общем-то, насколько я понимаю это зависит от компилятора. Но если ты напишешь
место выделит все равно (в сегменте данных) , а будет ли выполнена инициализация или нет зависит от типа данных если это твой класс
CMyClass my_class;
то для него при старте приложения (до входа в твою main) будет вызван конструктор по умолчанию,
для встроенных типов инициализации выполнена не будет и там будет мусор если инициализирующее значение не указано явно
т.е.
long l; — тут мусор
а в
long l=5; — соотвественно в этом случае инициализируется 5
место будет выделено одназначно, но вообще в принципе если поставить static
т.е. static CMyClass my_class ;
т.е. переменная видна ТОЛЬКО в пределах модуля
компилятор может соптимизировать и убрать.... но это вряд ли...
Здравствуйте, Carc, Вы писали:
C>В общем-то, насколько я понимаю это зависит от компилятора. Но если ты напишешь C>место выделит все равно (в сегменте данных) , а будет ли выполнена инициализация или нет зависит от
.... C>компилятор может соптимизировать и убрать.... но это вряд ли...
Спасибо. Я так и думал. То есть, если в библиотеке есть класс типа
class B
{
...
static long data[100];
...
}
(есть вроде такой template называется monolite, где у класса все данные — static)
то даже если я нигде не буду его упоминать в своей программе, то оно всеравно сожрет эти самые 100*sizeof(long) байт. Тогда такие классы надоть в отдельные библиотеки помещать, получается. Этож убрать из проекта можно тока отключив библиотеку...
А может это дело как-то в шаблон обернуть, а? Типа, если не будет в программе инстанцирования, то и класса, собственно, не будет и памать занимать ненужные данные не будут. Так?
Здравствуйте, r2b2, Вы писали:
R>Здравствуйте, Carc, Вы писали:
C>>В общем-то, насколько я понимаю это зависит от компилятора. Но если ты напишешь C>>место выделит все равно (в сегменте данных) , а будет ли выполнена инициализация или нет зависит от R>.... C>>компилятор может соптимизировать и убрать.... но это вряд ли...
R>Спасибо. Я так и думал. То есть, если в библиотеке есть класс типа
R>class B R>{ R>... R>static long data[100]; R>... R>}
R>(есть вроде такой template называется monolite, где у класса все данные — static)
R>то даже если я нигде не буду его упоминать в своей программе, то оно всеравно сожрет эти самые 100*sizeof(long) байт. Тогда такие классы надоть в отдельные библиотеки помещать, получается. Этож убрать из проекта можно тока отключив библиотеку...
R>А может это дело как-то в шаблон обернуть, а? Типа, если не будет в программе инстанцирования, то и класса, собственно, не будет и памать занимать ненужные данные не будут. Так?
да нет! к классу это не относится в данном случае data разделяется между всеми обьектами класса B, и пока не будет создан первый экземпляр класса B никакая память конечно выделяться не будет.
Вот до чего доходит взаимопонимание, когда в рождество разбираешься с двумя плюсами, а не с двумя стаканами
Просто у слова static несколько значений.
если данные класса то имеются ввиду что такие данные разделяются между всеми обьектами этого класса (ну и наследникам достаются, но это зависит от типа наследования: обычное или виртуальное)
Здравствуйте, Carc, Вы писали:
C>да нет! к классу это не относится в данном случае data разделяется между всеми обьектами класса B, и пока не будет создан первый экземпляр класса B никакая память конечно выделяться не будет.
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, r2b2, Вы писали:
R>>(есть вроде такой template называется monolite, где у класса все данные — static)
C>Не template, а pattern, и не monolite, а monostate.
Упс, :-| простите... Апшибочка вышла... Точно — pattern monostate. Вот только я по-прежнему недогоняю (вот такой я тупой) Вот компилер, он чтож, разве не переводит такое:
class B
{
static int i;
...
}
_________
//cpp
,..
B::i = 10;
вот в такое:
namespase B
{
int i = 10;
...
}
перед тем как компилить? Эти записи будут компилиться одинаково? Оно ж и в использовании сильно похоже:
B::i += 12;
Но во втором случае место под int i будет зарезервировано с стеке данных программы вне зависимости от того, ссылаюсь ли я где-нито на эту переменную или нет. Вот я и заподозрил, что классы monostate так же жрут память под свои данные вне зависимости, юзаю я эти классы или нет — лишь бы библиотека была присоединена.
И, кстати, как там в этом pattern-е monostate насчет ссылки на объект? Если у объекта нет нестатических переменных, то на что будет ссылаться такая ссылка? Или там конструкторы запрещены, как в синглтоне? Функции-то ведь все статические, так что им указатель this не передается...
Здравствуйте, Carc, Вы писали:
C>пока не будет создан первый экземпляр класса B никакая память конечно выделяться не будет.
вот это неправда Ваша память всегда выделяется под статические данные класса, независимо от того, создаешь ты объект или нет. Другое дело — статические переменные функции. Под статические данные функции память выделяется при первом вызове этой самой функции.
Здравствуйте, denisku, Вы писали:
D> Другое дело — статические переменные функции. Под статические данные функции память выделяется при первом вызове этой самой функции.
Вот позволю себе усомниться. Насколько я разобрался, это не так. Под переменные функции (обычные, не статические) память выделяется в стеке. Вышли из функции — стек освободили — все переменные "пропали". В стеке невозможно выделить "статическую" память. Так что статические переменные функции так же выделяются в сегменте данных программы. А то, что они — в функции — дык это чисто вопрос ограничения области видимости.
Здравствуйте, r2b2, Вы писали:
R>Я — самоучка, так что сорри за глупые вопросы. R>Вот есть у меня допустим библиотека классов. И допустим есть там (несколько) классы, у которых есть static переменные-члены. (этож фактически получается те же глобальные переменные) Ну, например класс сделанный по шаблону Monolite. Вопрос. А если я не юзаю этот монолит в своей программе, его статические переменные всеравно будут у меня место занимать или нет? Вот если бы у меня вместо этого монолита были бы только его переменные и функции в намаспейсе, то компиллер ведь все равно выделит статическое место для этих переменный, пофиг использую я их или нет. Да? А вот в случае с монолитным классом?
1. Monostate. А не монолит...
2. Библиотека какая? Если скомпиленная в lib статическая, то все зависит от линкера. Линкер собирает объектные модули (и в библиотеке тож они сидят), поэтому если в одном модуле несколько классов, то он их все присобачит... А если каждый класс в отделном модуле, то, конечно, соберет только используемые.
3. Статические поля класса [b]всегда[/] инициализируются... Для встроенных типов это обнуление, для реализованных — вызов конструктора по умолчанию.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>1. Monostate. А не монолит...
Да, меня уже ткнули носом... извиняюсь, попутал... LVV>2. Библиотека какая? Если скомпиленная в lib статическая, то все зависит от линкера. Линкер собирает объектные модули (и в библиотеке тож они сидят), поэтому если в одном модуле несколько классов, то он их все присобачит... А если каждый класс в отделном модуле, то, конечно, соберет только используемые. LVV>3. Статические поля класса [b]всегда[/] инициализируются... Для встроенных типов это обнуление, для реализованных — вызов конструктора по умолчанию.
Библиотека статическая. Большое спасибо за ответ. Тогда еще один — до кучи, что б уж всю ясность выяснить... Что, если static переменная в шаблоне класса? Если инстанцирования этого класса нигде в программе нет, то, оно вроде, и класса нет, сталобыть, память выделяться не будет? А можно ли static в шаблонах объявлять? Его ж мало объявить в классе, его ж надол реализовать, как же это в случае шаблонного класса сделать? И если инстанцировали этот шаблон дважды — раз для одного типа, а второй — для другого, траблов со static переменной не будет?
Здравствуйте, r2b2, Вы писали:
LVV>>3. Статические поля класса [b]всегда[/] инициализируются... Для встроенных типов это обнуление, для реализованных — вызов конструктора по умолчанию.
R>Библиотека статическая. Большое спасибо за ответ. Тогда еще один — до кучи, что б уж всю ясность выяснить... Что, если static переменная в шаблоне класса? Если инстанцирования этого класса нигде в программе нет, то, оно вроде, и класса нет, сталобыть, память выделяться не будет? А можно ли static в шаблонах объявлять? Его ж мало объявить в классе, его ж надол реализовать, как же это в случае шаблонного класса сделать? И если инстанцировали этот шаблон дважды — раз для одного типа, а второй — для другого, траблов со static переменной не будет?
Статические поля в шаблоне — сколько угодно... НО!!!!! Если ты прописываешь статическое поле, то обязан дать его определение — отдельно от класса. А этого достаточно, чтобы шаблон инстанцировался (естественно, только статические поля — остальное-то ты не инстанцировал!). А уж определения давай — какие тебе требуется. Если тип поля зависит от типа шаблона — то это просто разные инстанцированные классы будут...
смтори сюда...
Статические элементы в шаблонах
В классе-шаблоне, конечно, разрешено, объявлять и статические методы, и статические поля, однако нужно учесть, что каждая конкретизация обладает собственной копией статических членов. Это естественно, так как при разных инстанцированиях получаются фактически разные конкретные классы. Рассмотрим простой пример. Напишем простой класс-шаблон со статическими полями и статическим методом для вывода на экран (листинг 7.16). Подключать его к другим модулям программы сначала будем по модели включения.
//Листинг 7.16. Класс-шаблон со статическими элементами
//----------------------------файл StaticField.h#ifndef StaticField
#define StaticField
#include <iostream>
template <class T>
class Static
{ static T t; // зависимое имяstatic int count; // независимое имяpublic:
Static (){++count; } // конструктор считает объекты
~Static (){--count; } // деструкторstatic void print(T x = t);
};
template <class T> int Static<T>::count = 0; // счетчик объектовtemplate <class T> T Static<T>::t = T(); // определение ttemplate <> int Static<int>::t = 55; // специализация ttemplate <> double Static<double>::t = 155; // специализация ttemplate <class T> // реализация методаvoid Static<T>::print(T x)
{ std::cout << x <<" "<< count;
t = x;
}
#endif
В классе определен счетчик объектов — статическое поле count. Это поле не зависит от параметра шаблона, тем не менее, при его определении мы обязаны соблюдать синтаксис определения элементов класса-щаблона.
Определение статического поля t, тип которого зависит от шаблона, написано с инициализацией конструктора без аргументов T(), хотя можно этого не делать, так как он и так будет вызван по умолчанию. Стандарт разрешает специализировать статические поля, что мы и проделали для аргументов int и double. Специализаций статического поля вполне достаточно, чтобы компилятор смог инстанцировать классы Static<int> и Static<double>. Соответственно, для каждого из классов создаются статические поля-счетчики count; в первом классе инстанцируется статическое поле static int t, которому присваивается значение 55, и статический метод void print(int). Во втором классе инстанцируются статическое поле static double t, которое инициализируется значением 155.0, и статический метод void print(double).
Далее прописано обычное определение метода класса-шаблона, метод получает в качестве параметра по умолчанию статическое поле класса, и имеет побочный эффект — присваивает значение своего параметра статическому полю.
Поэкспериментируем с этим классом-шаблоном и его статическим методом print() (листинг 7.17).
//Листинг 7.17. Статические элементы шаблона – модель включения#include"StaticField.h"// модель включения#include <iostream>
using namespace std;
Static<long> r; // глобальный объектint main()
{ // объектов типа Static<double> не существует
Static<double>::print(); cout << endl; // значение по умолчанию
Static<double>::print(234); cout << endl; // изменили значение поля t
Static<double> r; // локальный объект создан
Static<double>::print(); cout << endl; // значение поля t = 234.0
// один объект типа Static<long> уже существует!
Static<long>::print(); cout << endl; // значение 0
Static<long>::print(4321); cout << endl; // изменили значение поля t
r.print(); cout << endl; // локальный объект
::r.print(); cout << endl; // глобальный объект
Static<int> t;
Static<int>::print(); cout << endl;
Static<int>::print(100); cout << endl;
return 0;
}
Сначала объявляется глобальный объект r. Соответственно создаются статические элементы класса Static<long>:
статическое поле count, не зависящее от аргумента шаблона;
статическое поле static long t, проинициализированное 0;
статический метод void print(long);
Создать глобальный объект того же типа с тем же именем в другом модуле нам не удастся — линкер сообщит о повторном определении.
Далее входим в функцию main() и вызываем статический метод
Static<double>::print();.
Программа выдаст на экран
155 0
Выводится значение поля static double t, присвоенное параметру по умолчанию, и количество объектов типа Static<double>, равное нулю – естественно, так как объектов мы не создавали. Далее вызывается тот же метод, но с явно заданным параметром 234. На экран выводится
234 0
Количество объектов по-прежнему равно нулю.
Создаем локальный объект типа Static<double> с именем r, он перекрывает глобальный объект r типа Static<long>. Тем не менее, статические поля count и t заново не создаются. При вызове метода Static<double>::print(); на экран выводится
234 1
Это означает, что используется значение того же поля t, которое было изменено в предыдущем вызове, и существует один объект.
Далее выполняются два вызова
Первый выводит на экран числа 0 и 1, которые соответствуют значению поля static long t, и количеству объектов типа Static<long>. Второй вызов выводит 4321 и 1 соответственно.
Далее программа демонстрирует вызов статического метода для конкретного объекта: локального типа Static<double> и глобального типа Static<long>. Тем не менее, выводятся те значение поля t, которые были присвоены ранее.
И наконец, демонстрируется вывод и изменение значения статического поля t, для специализации int: сначала значение присвоенное при определении, а затем новое.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!