Напоминание про inline и static. Синглтон. — различия между версиями
Katepol (обсуждение | вклад) (→Inline) |
Katepol (обсуждение | вклад) (→Статические переменные) |
||
Строка 46: | Строка 46: | ||
==Статические переменные== | ==Статические переменные== | ||
Если уж очень нужны глобальные переменные, лучше использовать статические переменные. Ключевое слово '''static''' обеспечивает защиту от перекрытия имен. Static может использоваться в 5 контекстах: | Если уж очень нужны глобальные переменные, лучше использовать статические переменные. Ключевое слово '''static''' обеспечивает защиту от перекрытия имен. Static может использоваться в 5 контекстах: | ||
− | + | '''1. Статические глобальные переменные''' | |
− | == | + | <source lang="cpp"> |
− | + | // 1.cpp | |
− | == | + | static int i = 0; |
− | + | </source> | |
+ | Такое объявление переменной делает ее глобальной в пределах одного cpp файла, в данном случае - 1.cpp. | ||
+ | Если объявить статическую переменную i в заголовочном файле, то в каждом файле, в который будет подключен этот header, будет по одной собственной i. | ||
+ | |||
+ | ''Замечание: типы линковки.'' | ||
+ | Линковка бывает: | ||
+ | * external - функции и переменные между модулями; | ||
+ | * internal - внутри одного модуля. Пример использования - счетчик открытых файлов. | ||
+ | |||
+ | '''2. Статические функции''' | ||
+ | Внутренняя линковка (internal). | ||
+ | Можно создавать разные функции с одинаковыми сигнатурами. Так как они определяются во время вызова, то могут и встроиться :). | ||
+ | Пример: можно в каждом cpp файле создать свою функцию static void test(). Напомню, что ключевое слово static защищает от перекрытия имен. | ||
+ | |||
+ | '''3. Статические локальные переменные''' | ||
+ | Рассмотрим следующую функцию: | ||
+ | <source lang="cpp"> | ||
+ | void print (double x) { | ||
+ | static int i = 0; | ||
+ | std::cout << (++i) << x << std::endl; | ||
+ | } | ||
+ | </source> | ||
+ | Переменная i хранится не хранится на стеке (А ГДЕ?). По сути, она является глобальной переменной, но ее областью видимости является только функция print. | ||
+ | |||
+ | Если сделать функцию print статической и вставить в несколько cpp файлов, то у каждого print будет свой счетчик i и своя реализация. А если сделать ее inline, то 1 общая реализация. | ||
+ | |||
+ | Рассмотрим еще один пример: | ||
+ | <source lang="cpp"> | ||
+ | void print (char const * fn, double x) { | ||
+ | static int i = 0; | ||
+ | static ofstream file(fn) = q(); // q() - некоторая функция | ||
+ | file << (++i) << x << endl; | ||
+ | } | ||
+ | * Если бы переменная ofstream file не была статической, то при каждом входе в print файл открывался бы заново. | ||
+ | * Т.к. file - статическая, то при каждом входе в print | ||
+ | </source> | ||
+ | |||
+ | '''4. Статические члены класса''' | ||
+ | '''5. Статические методы класса''' | ||
==Синглтон== | ==Синглтон== |
Версия 13:00, 23 апреля 2011
Inline
Рассмотрим некоторую inline функцию:
inline void f() {}
Где ее разместить: в cpp или в header'e?
1) При размещении любой функции в заголовочном файле, если данный header включен в несколько файлов вашего проекта, проект упадет при линковке, если ваша функция не inline.
2) Ключевое слово inline обязывает программиста размещать такую функцию в header'e, так как
- определение функции должно быть видно из того места в коде, где она используется;
- если разделить определение и тело inline функции, то ее можно будет использовать только в том cpp файле, в котором находится ее тело.
Если определить метод внутри класса, то он автоматически становится inline:
class T {
int size_;
public:
size_t getSize() const { // inline!
return size_;
}
};
Шаблонные функции - тоже inline, по очевидной причине: шаблонная функция должна быть определена к моменту вызова (при инстанциировании).
template <typename T>
void swap (T & a, T & b) {
...
}
Глобальные переменные
Что мы о них знаем? Что их не нужно использовать :), так как невозможно спрогнозировать, что лежит в этой переменной. Если у нас все же есть глобальная переменная и она определена в нескольких cpp файлах, то наша программа упадет при линковке. Избежать этого позволяет ключевое слово extern:
// 1.cpp
int i = 0;
// 2.cpp
extern int i; // extern указывает на то, что i определена где-то снаружи
На самом деле, перед любым объявлением функции автоматически ставится extern (можно явно писать, ошибки не будет).
Статические переменные
Если уж очень нужны глобальные переменные, лучше использовать статические переменные. Ключевое слово static обеспечивает защиту от перекрытия имен. Static может использоваться в 5 контекстах: 1. Статические глобальные переменные
// 1.cpp
static int i = 0;
Такое объявление переменной делает ее глобальной в пределах одного cpp файла, в данном случае - 1.cpp. Если объявить статическую переменную i в заголовочном файле, то в каждом файле, в который будет подключен этот header, будет по одной собственной i.
Замечание: типы линковки. Линковка бывает:
- external - функции и переменные между модулями;
- internal - внутри одного модуля. Пример использования - счетчик открытых файлов.
2. Статические функции Внутренняя линковка (internal). Можно создавать разные функции с одинаковыми сигнатурами. Так как они определяются во время вызова, то могут и встроиться :). Пример: можно в каждом cpp файле создать свою функцию static void test(). Напомню, что ключевое слово static защищает от перекрытия имен.
3. Статические локальные переменные Рассмотрим следующую функцию:
void print (double x) {
static int i = 0;
std::cout << (++i) << x << std::endl;
}
Переменная i хранится не хранится на стеке (А ГДЕ?). По сути, она является глобальной переменной, но ее областью видимости является только функция print.
Если сделать функцию print статической и вставить в несколько cpp файлов, то у каждого print будет свой счетчик i и своя реализация. А если сделать ее inline, то 1 общая реализация.
Рассмотрим еще один пример:
void print (char const * fn, double x) {
static int i = 0;
static ofstream file(fn) = q(); // q() - некоторая функция
file << (++i) << x << endl;
}
* Если бы переменная ofstream file не была статической, то при каждом входе в print файл открывался бы заново.
* Т.к. file - статическая, то при каждом входе в print
4. Статические члены класса 5. Статические методы класса