![](/img/trans.png)
[英]Why Visual Studio doesn't install vcvarsall.bat and DIA SDK
[英]Why does iostream require the exception handler to be called while using vcvarsall.bat to compile 'Hello World'?
嘗試在命令行中使用 vcvarsall.bat 編譯以下代碼會引發警告,指出代碼中需要異常處理程序,但在使用/EHsc
之前未調用。
代碼:
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
批處理文件:
@echo off
cl C:\Development\..\basicmath.cpp
警告:
C:\...\ostream(746): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:...\basicmath.cpp(10): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' being compiled
ostream 第 746 行的第 743 - 754 行(來自錯誤)是 _TRY:
if (!_Ok) {
_State |= ios_base::badbit;
} else { // state okay, insert
_TRY_IO_BEGIN
if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left) {
for (; 0 < _Pad; --_Pad) { // pad on left
if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
_State |= ios_base::badbit; // insertion failed, quit
break;
}
}
}
將 /EHsc 添加到我的批處理文件將允許它運行,但我想知道這是為什么。 為什么 output 文件中的這段代碼需要調用 EHsc?
MSDOCS 說 EHsc 用於清理以防止 memory 泄漏,是什么導致了泄漏,為什么他們需要外部程序來修復泄漏而不是在同一個文件中修復它(這聽起來可能很粗魯,但它只是無知)?
編輯:感謝您指出它是警告而不是錯誤。
按照文檔的建議,將/EHs
/EHsc
添加到您的編譯選項中。 如果您需要在 Unix 機器上執行相同的代碼,它是關於異常處理的最便攜的選項。
這個問題有兩個部分。 首先是iostream
中出現警告的原因,其次是警告的含義。
為什么iostream
中有異常?
C++ 中流的默認行為是無異常的——任何失敗都通過設置一個內部失敗位來表示,可以通過eof()
、 fail()
和bad()
函數訪問。 但是,您可以通過在 stream 上使用exceptions()
方法將此行為更改為在失敗時引發異常。 您可以選擇哪些失敗位觸發異常,但要點是代碼必須按標准存在。 警告似乎只分析了這一點 - 它注意到發生throw
的可能路徑並報告警告。
警告是什么意思?
從微軟文檔(強調我的):
默認情況下(即,如果未指定
/EHsc
、/EHs
EHs 或/EHa
選項),編譯器在本機 C++catch(...)
子句中支持 SEH 處理程序。 但是,它也會生成僅部分支持 C++ 異常的代碼。 默認的異常展開代碼不會因為異常而破壞 go 超出 scope 的 try 塊之外的自動 C++ 對象。
問題是(出於某種原因)MSVC 編譯器默認生成的程序集根據標准是錯誤的。 拋出異常時不會執行堆棧展開,這可能會導致 memory 泄漏和其他意外行為。
一個正確的示例 C++ 代碼,在默認設置下具有 memory 泄漏:
void foo()
{
std::string str = "This is a very long string. It definitely doesn't use Small String Optimization and it must be allocated on the heap."
std::cout << str;
throw std::runtime_error{"Oh no, something went wrong"};
}
int main()
{
try
{
foo();
}
catch (std::exception&)
{
// str in foo() was possibly not released, because it wasn't deleted when exception was thrown!
}
}
所以最終的答案是:
/EHa
/EHs
EHs 以兼容 C++ 標准和可移植性/EH
設置為一種或另一種,否則在使用異常時您將不得不處理奇怪的行為。這是一個警告,因此您當前的程序可以正常編譯。 但是這樣的程序會出現問題:
#include <exception>
#include <iostream>
struct A{
A(int x):x(x) {
std::cout<<"Contructed A::"<<x<<'\n';
}
~A() {
std::cout<<"Destructed A::"<<x<<'\n';
}
private:
int x;
};
void foo() {
A a{2};
throw std::bad_exception{};
}
int main()
{
A a {1};
try {
foo();
} catch(const std::bad_exception& ex) {
std::cout<<ex.what()<<'\n';
}
return 0;
}
使用cl test.cpp
產生 output:
Contructed A::1
Contructed A::2
bad exception
Destructed A::1
使用cl test.cpp /EHsc
產生:
Contructed A::1
Contructed A::2
Destructed A::2
bad exception
Destructed A::1
警告C4530的文檔解釋了此行為:
當 /EHsc 選項未啟用時,在拋出的 function 和捕獲異常的 function 之間的堆棧幀中的自動存儲對象不會被破壞。 只有在 try 或 catch 塊中創建的自動存儲對象會被破壞,這可能導致嚴重的資源泄漏和其他意外行為。
這解釋了當程序未使用/EHsc
編譯時a {2}
未被破壞。
而且當然,
如果在您的可執行文件中不可能拋出異常,您可以放心地忽略此警告。
所以,對於像這樣的程序
#include <cstdio>
int main()
{
std::printf("hello world\n");
return 0;
}
cl.exe
安靜地編譯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.