2016-02-23 1 views
0

Рассмотрим следующий фрагмент кода:AV на Ctrl-C в деструкторе глобальной переменной

#include "stdafx.h" 
#include <cstdlib> 
#include <iostream> 
#include <Windows.h> 

using namespace std; 

class A 
{ 
public: 
    ~A() 
    { 
     cout << "I am about to die" << endl; 
    } 
}; 

A a; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    while (true) 
    { 
     cout << "Waiting for ctrlc" << endl; 
     Sleep(1000); 
    } 
} 

При нажатии Ctrl-C Я получаю AV с следующим стеком вызовов:

0:001> kn 
# Child-SP   RetAddr   Call Site 
00 000000c0`dcdbf420 000007fe`9244fab9 MSVCP120D!std::locale::locale+0x2e [f:\dd\vctools\crt\crtw32\stdhpp\xlocale @ 324] 
01 000000c0`dcdbf450 000007fe`92454e25 MSVCP120D!std::ios_base::getloc+0x29 [f:\dd\vctools\crt\crtw32\stdhpp\xiosbase @ 424] 
*** WARNING: Unable to verify checksum for JustPlayC.exe 
02 000000c0`dcdbf490 000007f7`524c33c0 MSVCP120D!std::basic_ios<char,std::char_traits<char> >::widen+0x25 [f:\dd\vctools\crt\crtw32\stdhpp\ios @ 127] 
03 000000c0`dcdbf4f0 000007fe`9246570e JustPlayC!std::endl<char,std::char_traits<char> >+0x40 [c:\program files (x86)\microsoft visual studio 12.0\vc\include\ostream @ 999] 
04 000000c0`dcdbf520 000007f7`524c2cb1 MSVCP120D!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x2e [f:\dd\vctools\crt\crtw32\stdhpp\ostream @ 201] 
05 000000c0`dcdbf550 000007f7`524cefb1 JustPlayC!A::~A+0x41 
06 000000c0`dcdbf580 000007fd`edd558c3 JustPlayC!`dynamic atexit destructor for 'a''+0x21 
07 000000c0`dcdbf5b0 000007fd`edd551b3 MSVCR120D!doexit+0x133 [f:\dd\vctools\crt\crtw32\startup\crt0dat.c @ 628] 
08 000000c0`dcdbf620 000007fd`edd55aeb MSVCR120D!_cexit+0x13 [f:\dd\vctools\crt\crtw32\startup\crt0dat.c @ 449] 
09 000000c0`dcdbf650 000007fd`edd559c1 MSVCR120D!__CRTDLL_INIT+0x10b [f:\dd\vctools\crt\crtw32\dllstuff\crtlib.c @ 325] 
0a 000000c0`dcdbf6a0 000007fe`d916ecef MSVCR120D!_CRTDLL_INIT+0x31 [f:\dd\vctools\crt\crtw32\dllstuff\crtlib.c @ 215] 
0b 000000c0`dcdbf6d0 000007fe`d9180f6c ntdll!LdrpCallInitRoutine+0x3f 
0c 000000c0`dcdbf720 000007fe`d9180e0c ntdll!LdrShutdownProcess+0x142 
0d 000000c0`dcdbf830 000007fe`d612870f ntdll!RtlExitUserProcess+0xac 
0e 000000c0`dcdbf870 000007fe`d61286e7 KERNELBASE!DefaultHandler+0xf 
0f 000000c0`dcdbf8a0 000007fe`d8841842 KERNELBASE!CtrlRoutine+0x9b 
10 000000c0`dcdbf990 000007fe`d9174f45 KERNEL32!BaseThreadInitThunk+0x1a [d:\win8_gdr\base\win32\client\thread.c @ 65] 
11 000000c0`dcdbf9c0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d 

Может кто-нибудь помочь мне понять, что происходит? Похоже, что локаль MSVCP получает uninitalized перед глобальным деструктором переменной, который полагается на локаль? Каков правильный способ обойти это?

+0

Почему вы не устанавливаете обработчик сигнала и не закрываете программу правильно? –

+0

Ну, конечно, есть много альтернатив. Но я хотел бы понять порядок неинициализации, который привел к AV. – Klark

+0

Порядок инициализации и уничтожения глобальных переменных не указан. – songyuanyao

ответ

0

Из моего понимания того, как работает среда выполнения, является то, что глобальная переменная A создается во время инициализации среды выполнения, до вызова main(). Поэтому он привязан к языку базовой ОС, а не к локальному приложению в этом случае. Поэтому локаль приложения применяется до разрушения глобального. Как заметил кто-то, если вы хотите, чтобы деструктор использовал локаль приложения, лучший способ - использовать обработчик для ctrl-c. Однако, если этот объект был построен внутри основного, тогда он становится реальной конструкцией во время выполнения и не пострадает от этой проблемы.