Этот сочетает в себе как оригинальный ответ Роба, так и обновление Pilau за 2016 год
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
// Opera 8.0+ (UA detection to detect Blink/v8-powered Opera)
var isFirefox = typeof InstallTrigger !== 'undefined'; // Firefox 1.0+
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
// At least Safari 3+: "[object HTMLElementConstructor]"
var isChrome = !!window.chrome && !isOpera; // Chrome 1+
var isIE = /*@cc_on!@*/false || !!document.documentMode;
// Edge 20+
var isEdge = !isIE && !!window.StyleMedia;
// Chrome 1+
var output = 'Detecting browsers by ducktyping:
';
output += 'isFirefox: ' + isFirefox + '
';
output += 'isChrome: ' + isChrome + '
';
output += 'isSafari: ' + isSafari + '
';
output += 'isOpera: ' + isOpera + '
';
output += 'isIE: ' + isIE + '
';
output += 'isIE Edge: ' + isEdge + '
';
document.body.innerHTML = output;
Мне было любопытно на предмет этого так, я записал следующую тестовую программу и скомпилировал ее с g ++ версия 4.1.2.
include <iostream>
#include <string>
using namespace std;
class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}
~test()
{
cout << _name << " destroyed" << endl;
}
string _name;
};
test t("global variable");
void f()
{
static test t("static variable");
test t2("Local variable");
cout << "Function executed" << endl;
}
int main()
{
test t("local to main");
cout << "Program start" << endl;
f();
cout << "Program end" << endl;
return 0;
}
, результаты не были тем, что я ожидал. Конструктора для статического объекта не вызывали до первого раза была вызвана функция. Вот вывод:
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
Некоторая соответствующая формулировка из Стандарта C++:
3.6.2 Инициализаций нелокального [basic.start.init]
1
объектов устройство хранения данных для объектов со статической продолжительностью хранения ( basic.stc.static) должно быть инициализировано нулем ( dcl.init), прежде чем любая другая инициализация произойдет. Объекты типов POD ( basic.types) со статической продолжительностью хранения, инициализированной с константными выражениями ( expr.const), должны быть инициализированы, прежде чем любая динамическая инициализация происходит. Объекты объема пространства имен со статической продолжительностью хранения, определенной в той же единице перевода и динамично инициализированной, должны быть инициализированы в порядке, в котором их определение появляется в единице перевода. [Отметьте: dcl.init.aggr описывает порядок, в котором инициализируются совокупные участники. Инициализация локальных статических объектов описана в stmt.dcl.]
[больше текста ниже добавления большего количества свобод для разработчиков компилятора]
6.7 операторов объявления [stmt.dcl]
...
4
нулевая инициализация ( dcl.init) всех локальных объектов со статической продолжительностью хранения ( basic.stc.static) выполняется, прежде чем любая другая инициализация происходит. Локальный объект типа POD ( basic.types) со статической продолжительностью хранения, инициализированной с константными выражениями, инициализируется, прежде чем ее блок сначала вводится. Реализации разрешают выполнить раннюю инициализацию других локальных объектов со статической продолжительностью хранения при тех же условиях, что реализации разрешают статически инициализировать объект со статической продолжительностью хранения в объеме пространства имен ( basic.start.init). Иначе такой объект инициализируется, первый контроль времени проходит через свое объявление; такой объект считают инициализированным после завершения его инициализации. Если выходы инициализации путем выдачи исключения, инициализация не завершена, таким образом, ее попробуют еще раз, следующий контроль времени вводит объявление. Если управление повторно вводит объявление (рекурсивно), в то время как объект инициализируется, поведение не определено. [ Пример:
int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; }
- пример конца ]
5
деструктор для локального объекта со статической продолжительностью хранения будет выполняться, если и только если переменная была создана. [Отметьте: basic.start.term описывает порядок, в котором уничтожаются локальные объекты со статической продолжительностью хранения.]
Память для всех статических переменных выделяется при загрузке программы. Но локальные статические переменные создаются и инициализировали в первый раз, когда они используются, не при запуске программы. Существует некоторое хорошее чтение об этом и помехи в целом, здесь . В целом я думаю, что некоторые из этих проблем зависят от реализации, особенно если Вы хотите знать, где в памяти этот материал будет расположен.
Компилятор выделит статическую переменную (переменные), определенную в функции foo
при загрузке программы, однако компилятор также добавит некоторые дополнительные инструкции (машинный код) к Вашей функции foo
так, чтобы в первый раз это было вызвано, этот дополнительный код инициализирует статическую переменную (например, вызов конструктора, если применимо).
@Adam: Это негласно инжекция кода компилятором является причиной результата, который Вы видели.
Статические переменные выделяются в сегменте кода - они - часть исполняемого изображения, и так уже отображаются в инициализированном.
Статические переменные в функциональном объеме рассматривают то же, обзор является просто конструкцией уровня языка.
Поэтому Вам гарантируют это, статическая переменная будет инициализирована к 0 (если Вы не определите что-то еще), а не неопределенное значение.
существуют некоторые другие фасеты к инициализации, можно воспользоваться преимуществом прочь - например, совместно использованные сегменты позволяют различным экземплярам исполняемого файла, работающего сразу получать доступ к тем же статическим переменным.
В C++ (глобально ограниченный по объему) статическим объектам вызвали их конструкторов как часть запуска программы под управлением библиотеки времени выполнения C. Под Visual C++, по крайней мере, порядком, в котором инициализируются объекты, можно управлять прагма init_seg .
Или это инициализируется, когда doSomething () сначала называют?
Да, это. Это, среди прочего, позволяет Вам инициализировать глобально полученные доступ структуры данных, когда это является соответствующим, например, в блоках попытки/выгоды. Например, вместо
int foo = init(); // bad if init() throws something
int main() {
try {
...
}
catch(...){
...
}
}
можно записать
int& foo() {
static int myfoo = init();
return myfoo;
}
и использовать его в блоке попытки/выгоды. На первом вызове будет инициализирована переменная. Затем на первых и следующих вызовах его значение будет возвращено (ссылкой).