今天調試caffe代碼的時候遇到一個問題,在switch中添加調試代碼,發生錯誤,錯誤信息如標題,解決辦法是下面這篇博文裏描述的
The following is not allowed:
{
case 1:
int a = 6;
//stuff
break;
case 2:
//stuff
break;
}
The following is allowed:
{
case 1:
{
int a = 6;
//stuff
}
break;
case 2:
//stuff
break;
}
來自實際項目的一段代碼,簡化形式如下:
switch (t)
{
case 0:
int a = 0;
break;
default:
break;
}
有什麼問題嗎?似乎沒有。請用編譯器編譯一下……
嗯?!一個錯誤“error C2361: initialization of 'a' is skipped by 'default' label”。這怎麼可能?
幾番思琢,悟出解釋:C++約定,在塊語句中,對象的作用域從對象的聲明語句開始直到塊語句的結束,也就是說default標號後的語句是可以使用對象a的。如果程序執行時從switch處跳到default處,就會導致對象a沒有被正確地初始化。確保對象的初始化可是C++的重要設計哲學,所以編譯器會很嚴格地檢查這種違例情況,像上述的示例代碼中default語句後面並沒有使用a,但考慮到以後代碼的改動可能無意中使用,所以一樣被封殺。
明白了原因,解決起來就很容易了。只要明確地限制對象a的作用域就行了。
switch (t)
{
case 0:
{ //added for fix problem
int a = 0;
break;
} //added for fix problem
default:
break;
}
如果確實需要在整個switch語句中使用對象a,那就把int a = 0;移到switch語句之前即可。不過從原先的語句看,其意圖似乎並不是這樣的,所以推薦前面的解決方案。
結束了嗎?沒有。讓我們繼續考究錯誤提示信息中“initialization”(也就是初始化)的確切含義。C++很看重初始化,所以往往會給我們造成一種錯覺,似乎對象在定義處一定會經過初始化過程。真實情況如何呢?還是用實例來證明吧。
switch (t)
{
case 0:
int a;
a = 0;
break;
default:
break;
}
編譯,這次沒有報錯。很明顯int a;定義了對象,但沒有進行初始化,否則就應該報告原先的錯誤。
再看看用戶自定義類型。
class B
{
};
switch (t)
{
case 0:
B b;
break;
default:
break;
}
編譯結果也沒有錯誤,所以沒有提供構造器的類仍然沒有初始化過程。
如果給類加入構造器,情況就不同了。
class B
{
public: //added for initialization
B(){} //added for initialization
};
這樣就能重現原先的錯誤。證明有了構造器,編譯器就將進行初始化處理並對之進行安全檢查。
從上面的實驗,可以直觀地體驗到一些基本的C++觀念和原理,並提高認識深度。
1.int a = 0;既是聲明也是定義,還包括初始化;int a;是聲明還是定義依上下文而定,但如果是定義就不會包括初始化;a = 0;僅僅是賦值語句,在此句前對象已經存在了。
2.爲了避免不必要的開銷,默認情況下,即程序員沒有在代碼中明確指示時,編譯器不提供初始化過程。某些需要確保初始化的類,請提供構造器。這裏透露出一個C++的設計哲學:通常你會面對多種選擇,所以請精確地控制代碼,其收益則是可以自由取捨調配的安全性、速度、內存開銷等程序特性。
3.嚴密注意程序中標號的使用情況,特別是case、default等常規標號,否則他們可能會破壞對象的正確狀態。如果提供了對象初始化,則能夠獲得編譯器的額外幫助。
問題:
1>
"
如果程序執行時從switch處跳到default處,就會導致對象a沒有被正確地初始化。確保對象的初始化可是C++的重要設計哲學,所以編譯器會很嚴格地檢查這種違例情況,像上述的示例代碼中default語句後面並沒有使用a,但考慮到以後代碼的改動可能無意中使用,所以一樣被封殺。
"
它還會考慮到以後代碼的改動可能無意中使用這種情況嗎?
2>
class B
{
};
爲什麼聲明一個B對象時作者說沒有初始化,類不是在沒有聲明構造函數時會用它的默認構造函數來初始化對象嗎?爲什麼作者說沒有初始化呢?
3>
爲什麼說沒有初始化就會出問題呢?在C++中所有對象一定要初始化?不是這樣的吧.
作者好像就這個意思啊.!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面是我的分析:
case_init.cpp:9: error: jump to case label
case_init.cpp:7: error: crosses initialization of `int a'
首先在這裏作者提到問題出在本地(local)變量或者叫做自動變量的作用域範圍,點的很好。本地變量的作用域僅在花括號之間。於是方案1:
其實再深入一步,就完全清楚了,我把程序改動了一下,加了幾個打印語句: