Статическая переменная в c ++ [duplicate]

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

320
задан allyourcode 9 October 2014 в 01:55
поделиться

4 ответа

Время жизни переменных функции static начинается с первого раза [0], поток программы встречает декларацию и заканчивается при завершении программы. Это означает, что время выполнения должно выполнять некоторую книгу, чтобы уничтожить ее, только если она была построена.

Кроме того, поскольку стандарт говорит о том, что статические объекты деструкторов должны выполняться в обратном порядке завершения их построения [1], а порядок построения может зависеть от конкретного прогона программы, порядок

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str; << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Выход:

C:> sample.exe Создано в foo Разрушено в foo

C:> sample.exe 1 Создано в if Создано в foo Разрушено в foo Разрушено в if

C:> sample.exe 1 2 Создано в foo Создано, если уничтожено, если уничтожено в foo

[0] Поскольку C ++ 98 [2] не имеет ссылки на несколько потоков, как это будет вести себя в многопоточной среде, является неуказанным и может быть проблематичным, поскольку упоминается Родди .

[1] Раздел C ++ 98 3.6.3.1 [basic.start.term]

[2] В C ++ 11 статики инициализируются безопасным потоком, это также известно как Magic Statics .

192
ответ дан Community 19 August 2018 в 05:23
поделиться
  • 1
    Для простых типов без каких-либо побочных эффектов c'tor / d'tor, простая оптимизация для их инициализации аналогично глобальным простым типам. Это позволяет избежать проблем ветвления, флага и порядка уничтожения. Это не значит, что их жизнь ничем не отличается. – John McFarlane 29 October 2011 в 02:06
  • 2
    «деструкторы» глобальных объектов должны работать в обратном порядке завершения их построения ». здесь не применяется, поскольку эти объекты не являются глобальными. Порядок уничтожения местных жителей со статической или длительностью хранения потоков значительно сложнее, чем чистый LIFO, см. Раздел 3.6.3 [basic.start.term] – Ben Voigt 16 June 2015 в 14:10
  • 3
    Фраза "при завершении программы" не является строго правильным. Что относительно статистики в Windows dll, которые загружаются и выгружаются динамически? Очевидно, что стандарт C ++ вообще не касается сборок (было бы неплохо, если бы это было так), но выяснение того, что здесь говорит стандарт, было бы неплохо. Если фраза "при завершении программы" был бы включен, он технически сделает любую реализацию C ++ с динамически разгруженными сборками несоответствующими. – Roger Sanders 14 April 2017 в 12:25
  • 4
    @RogerSanders - это хороший момент, стандарт, который у меня есть (C ++ 11), говорит, что деструкторы объектов со статической продолжительностью хранения вызываются в результате возврата из main и в результате вызова std::exit . Можете ли вы указать мне часть стандарта, где он позволяет динамические библиотеки явно? – Motti 17 April 2017 в 19:41
  • 5
    @Motti Я не считаю, что стандарт явно разрешает динамические библиотеки, но до сих пор я также не думал, что в стандарте есть что-то конкретное, что противоречило его реализации. Конечно, строго говоря, здесь не говорится, что статические объекты не могут быть уничтожены ранее другими средствами, просто они должны быть уничтожены при возврате из основного или вызова std :: exit. Я думаю, довольно тонкая линия. – Roger Sanders 28 April 2017 в 00:26

Существующие объяснения на самом деле не полны без фактического правила из Стандарта, найденного в 6.7:

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

9
ответ дан Ben Voigt 19 August 2018 в 05:23
поделиться

FWIW, Codegear C ++ Builder не разрушает ожидаемый порядок в соответствии со стандартом.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... это еще одна причина не полагаться на порядок уничтожения!

117
ответ дан Roddy 19 August 2018 в 05:23
поделиться
  • 1
    Не хороший аргумент. Я бы сказал, что это скорее аргумент не использовать этот компилятор. – Martin York 29 October 2008 в 20:24
  • 2
    Хм. Если вы заинтересованы в создании портативного кода в реальном мире, а не просто в теоретическом переносном коде, я думаю, что полезно знать, какие области языка могут вызвать проблемы. Я был бы удивлен, если бы C ++ Builder был уникальным, не обращаясь с этим. – Roddy 29 October 2008 в 20:58
  • 3
    Я бы согласился, кроме того, что я бы назвал это как «какие компиляторы вызывают проблемы и какие области языка они делают в & quot; ;-П – Steve Jessop 30 October 2008 в 01:16
  • 4
    C ++ 0x требует, чтобы статическая инициализация была потокобезопасной. Так что будьте осторожны, но все будет только лучше. – deft_code 7 October 2010 в 06:05
  • 5
    Проблемы с порядком уничтожения можно избежать с помощью небольшой политики. статические / глобальные объекты (одиночные и т. д.) не должны обращаться к другим статическим объектам в своих телах методов. Они будут доступны только в конструкторах, где ссылочный / указатель может быть сохранен для последующего доступа в методах. Это не идеально, но нужно исправить 99 случаев, и случаи, которые он не заражает, явно подозрительны и должны быть пойманы в обзоре кода. Это еще не идеальное решение, поскольку политика не может быть применена на языке – deft_code 7 October 2010 в 06:15
  • 6
    Я немного нуб, но почему эта политика не может применяться на языке? – cjcurrie 21 January 2013 в 07:02
  • 7
    Начиная с C ++ 11, это уже не проблема. Ответ Мотти обновляется в соответствии с этим. – Nilanjan Basu 28 December 2017 в 20:24
121
ответ дан Roddy 30 October 2018 в 17:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: