2010-10-28 24 views
5

$ 5.2.11/7 - 「[注:根據 類型通過指針,左值或指針 數據成員從 的const_cast該擅自拋棄所造成的對象,寫入操作 的一個 常量-qualifier68)可以產生 未定義的行爲(7.1.5.1)。]」的const_cast和UB

此單元(C++ 03)的字眼是令人驚訝我。什麼是驚奇是兩件事。

a)首先,使用「可能」。爲什麼會'可能'?標準中的其他地方對於未定義的行爲非常確定

b)爲什麼要拋棄最初的const對象的常量不是直接的'未定義的行爲'。爲什麼UB被觸發需要寫入?

+0

我向讀者介紹Kaz Dragon的答案 - 「7.1.5.1/4」 - 我認爲如果原始對象沒有被聲明爲「const」,這不是UB。這個標準中的措辭是含混不清的。但是有一個故意編寫的代碼示例同時指出,通過'const_cast'ed ref/ptr寫入最初的非''contst'對象被定義,我認爲它比具有「depends」的段落更具權威性,並且「可以」在其中。 ;) – 2016-02-23 07:59:09

回答

4

a)首先,使用「可能」。爲什麼 它'可能'?在標準 等地均對 未定義行爲

不要太深入地使用這個詞可能在這裏非常明確的。關鍵是,在這種情況下拋出constness會導致未定義的行爲。

的C++標準使用「可能」或「可能會」經常,如:

1.3.12:未定義行爲可以也可以當本國際標準 任何省略明確 的描述預期行爲的定義。

強調我的。基本上,該標準使用如「is allowed to」中的「可能」一詞。

二)爲什麼會這樣虛擲的 常量性不會馬上「未定義 行爲」一個原本const對象 的。爲什麼UB被觸發需要寫入 ?

寫入會觸發UB,因爲可能會將const對象存儲在某些平臺上的只讀存儲器中。

+0

它並沒有真正回答我的第三個問題.... – Chubsdad 2010-11-04 07:06:31

1

我認爲這是因爲const對象可以存儲在只讀存儲器中。因此,寫入它會產生許多不同的效果:程序崩潰,分段錯誤或無效果。

3

我的理解是,如果所討論的對象基本上是一個const對象而不是一個常量指針或對一個本來不是const的對象的引用,那麼它只會是UB。

這個想法是,基本上是常量的數據可以加載到內存的只讀部分,寫入只是不會工作。但是,如果所討論的對象基本上是可變的,它將保證正常工作。

例:

const int x = 4; 
const int *y = x; 

*const_cast<int*>(x) = 3; // UB - the pointed-to object may 
          // be in read-only memory or whatever. 

int  a = 7; 
const int *b = a; 

*const_cast<int*>(b) = 6; // Not UB - the pointed-to object is 
          // fundamentally mutable. 

對於下面的註釋,因爲代碼看起來可怕在註釋:

在§7.1標準的5.1/4,給出的例子是:

int i = 2; 
const int * cip; // pointer to const int 
cip = &i;  // OK: cv-qualified access path to unqualified 
... 
int* ip; 
ip = const_cast <int *>(cip); // cast needed to convert const int* to int* 
*ip = 4;      // defined: *ip points to i, a non-const object 

所以這是特別允許的。

+0

我不同意。 C++標準。 §7.1.5.1/ 4說除了任何聲明mutable的類成員(7.1.1)都可以被修改外,任何修改const對象在其生命期內(3.8)的嘗試都會導致未定義的行爲**任何嘗試** – 2010-11-12 10:32:31

+1

@Alexey - 現在查看§7.1.5.1/ 4的例子,它恰好在您引用的地方。它特別允許這種情況。我已經將代碼添加到上面的答案中,因爲代碼在這裏看起來很糟糕。 – 2010-11-12 11:10:21

+0

對於'7.1.5.1/4'爲+1。我認爲這個問題中引用的措辭充其量是寫得不好,在最壞的情況下危險地相互矛盾。但我採用了一個故意編寫的代碼示例,聲稱這個定義比具有「依賴」和「可能」的段落更具權威性。 – 2016-02-23 07:55:58

3

對於你的第一個問題,如果可能產生未定義的行爲,那麼這並沒有使它更不明確。

對於第二部分,我想可能是因爲互操作性原因。例如,C沒有(或沒有,在C99之前)有一個const關鍵字,所以如果你想傳遞一個const對象到一個C函數,const必須被拋棄。所以C++標準規定只要沒有執行寫操作就允許這樣做。如果C函數是隻讀的,則可以安全地拋棄常量。

即使在C++中,不一致或不完整的const正確性也很常見。所以我們偶爾遇到這樣的情況,我們必須拋棄const來爲了傳遞一個const對象到一個不修改它的參數的函數,而是通過非const來接受它。

+0

等等...什麼?我很確定C89有'const'。請參閱http://flash-gordon.me.uk/ansi.c.txt中的第3.5.3節「類型限定符」。 – 2010-10-28 12:23:11

+0

C89具有const,但有很多舊的和/或蹩腳的但有用的C(甚至C++)API不會以任何方式使用它。 – 2010-10-28 13:34:54

+0

哦,很奇怪。我不知道是什麼讓我覺得它沒有。我立場糾正。 :) – jalf 2010-10-28 17:18:43