在下面的示例程式中,
為什么用戶定義的型別別的靜態和自動變數的輸出不同?
/* test.cpp */
/* SalesData Class */
class SalesData {
public:
SalesData() = default;
// other member funcations
private:
std::string bookNo;
unsigned int unitsSold;
double revenue;
};
/*
* Prints the SalesData object
*/
std::ostream& print(std::ostream &os, const SalesData &item) {
os << "ISBN :\'" << item.isbn() << "\', Units Sold :" << item.unitsSold
<< ", Revenue :" << item.revenue << ", Avg. Price :"
<< item.avgPrice() << std::endl;
return os;
}
int main(int argc, char *argv[]) {
SalesData s;
static SalesData s2;
print(cout, s);
print(cout, s2);
return 0;
}
程式的輸出是這樣的——
$ ./test
ISBN :'', Units Sold :3417894856, Revenue :4.66042e-310, Avg. Price :1.36352e-319
ISBN :'', Units Sold :0, Revenue :0, Avg. Price :0
靜態如何改變合成默認建構式中的場景?
uj5u.com熱心網友回復:
s默認建構式在和上具有相同的行為s2。不同之處在于,對于靜態區域變數,
在塊范圍內使用說明符 static 宣告的變數
or thread_local (since C 11)具有靜態or thread (since C 11)存盤持續時間,但在控制第一次通過它們的宣告時被初始化(除非它們的初始化是零或常量初始化,這可以在第一次進入塊之前執行)。
關于零初始化:
對于每個具有靜態
or thread-local (since C 11)存盤持續時間且不受常量初始化影響的命名變數,在任何其他初始化之前。
這意味著s2將首先進行零初始化,因為它的資料成員也被零初始化;然后main()通過默認建構式輸入它是默認初始化的。
uj5u.com熱心網友回復:
案例一
讓我們考慮一下SalesData s;。
在這種情況下,SalesData具有名稱的型別物件s是使用 的默認建構式構造的SalesData。另外,請注意,在這種情況下,變數s是本地 nonstatic。
接下來因為你:
- 沒有使用類內初始化器來初始化
unitsSold和revenue - 沒有使用建構式初始化器串列來初始化
unitsSold和revenue
這 2 個變數具有不確定的值。并且使用這些未初始化的變數會導致未定義的行為。
這意味著當你寫:
print(cout, s);//this calls print function
在print函式體內你有:
os << "ISBN :\'" << item.isbn() << "\', Units Sold :" << item.unitsSold
<< ", Revenue :" << item.revenue << ", Avg. Price :"
<< item.avgPrice() << std::endl; //this is undefined behavior
因此,在上面的陳述句中,您使用的是未初始化的變數unitsSold,revenue這會導致未定義的行為。
未定義的行為意味著任何事情1都可能發生,包括但不限于給出預期輸出的程式。但永遠不要依賴(或基于)具有未定義行為的程式的輸出。
這就是您在這種情況下看到這些數字(垃圾值)的3417894856原因4.66042e-310。所以不要依賴程式的輸出,因為它具有未定義的行為。
案例二
現在讓我們考慮 static SalesData s2;
從靜態區域變數的初始化檔案:
在塊范圍內使用說明符static或 thread_local 宣告的變數(自 C 11 起)具有靜態或執行緒(自 C 11 起)存盤持續時間,但在控制第一次通過其宣告時被初始化(除非它們的初始化為零或常量初始化,可以在第一次進入塊之前執行)。
現在從零初始化檔案開始:
在以下情況下執行零初始化:
- 對于每個具有靜態或執行緒區域(C 11 起)存盤持續時間且不受常量初始化影響的命名變數,在任何其他初始化之前。
這是最相關的部分:
零初始化的效果是:
如果 T 是非聯合型別別,則所有基類和非靜態資料成員都初始化為零,并且所有填充都初始化為零位。建構式(如果有)將被忽略。
讓我們將上面參考的這些陳述句應用于您的示例 static SalesData s2;
在這種情況下,變數s2是區域靜態的。這里發生了兩件事:
- 變數
s2初始化為零。這意味著它的所有非靜態資料成員都喜歡unitsSold并根據上面參考的陳述句revenue設定為。0這就是在這種情況下輸出數字全部0而不是一些垃圾值的原因。 - 接下來,使用默認建構式
s2對變數進行默認初始化。
1對于未定義行為的技術上更準確的定義,請參見此處提到:對程式的行為沒有限制。
uj5u.com熱心網友回復:
具有靜態存盤持續時間的變數在其動態初始化階段之前被初始化為零。
unitsSold并且revenue默認初始化。這使它們未初始化。在靜態存盤的情況下,之前的零初始化成立。在自動存盤的情況下,它們具有不確定的值。讀取不確定的值會導致程式的未定義行為。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/421514.html
標籤:
上一篇:試圖理解移動語意
