2008-12-10 135 views
81

我找不到關於const_cast的很多信息。我可以找到的唯一信息(堆棧溢出)是:const_cast是否安全?

const_cast<>()用於添加/刪除變量的const(ness)(或volatile- ness)。

這讓我很緊張。可以使用const_cast會導致意外的行爲?如果是這樣,什麼?

另外,什麼時候可以使用const_cast

+1

頂端回答忽視的東西,可能是可怕的,但顯而易見的是值得指出:它只是變得不安全_if試圖修改原來`const` object_經過一個去`const` -ed引用/指針。相反,如果你只是`const_cast`來解決一個糟糕的(或者,在我的情況下是懶惰的)spec'd API,它只接受一個非``const`引用,但只會在`const`方法中使用...沒有任何問題。 – 2015-12-22 01:39:30

回答

89

const_cast只有在您投射最初爲非const的變量時纔是安全的。例如,如果您有一個功能需要const char *的參數,並且您傳遞了可修改的char *,則可以安全地將該參數返回到char *並對其進行修改。但是,如果原始變量實際上是const,則使用const_cast將導致未定義的行爲。

void func(const char *param, size_t sz, bool modify) 
{ 
    if(modify) 
     strncpy(const_cast<char *>(param), sz, "new string"); 
    printf("param: %s\n", param); 
} 

... 

char buffer[16]; 
const char *unmodifiable = "string constant"; 
func(buffer, sizeof(buffer), true); // OK 
func(unmodifiable, strlen(unmodifiable), false); // OK 
func(unmodifiable, strlen(unmodifiable), true); // UNDEFINED BEHAVIOR 
+8

這不是真的。 C++標準。 5.1.1節說除了任何聲明mutable的類成員(7.1.1)都可以被修改以外,任何在其生命週期(3.8)修改const對象的嘗試都會導致未定義的行爲**任何嘗試**!沒有關於原始變量的文字。 – 2010-11-08 15:12:56

+18

@Alexey:原始變量是關於指向或引用的內容。您可以對非const對象採用const引用,因此將其轉換爲可寫引用是明確定義的行爲,因爲所引用的對象實際上並不是const。 – Puppy 2010-11-09 16:53:29

+0

@DeadMG:`你可以對非const對象進行const引用。就這樣。之後,你有一些const對象而不是非const對象。此外,有些情況下允許創建一個初始非const對象的const副本。例如,對於函數參數的情況。 – 2010-11-12 10:23:28

22

我覺得很難相信,這是你能找到的const_cast的只有信息。從second Google hit報價:

如果丟掉一個 對象的常量性已經明確 聲明爲const,並嘗試 修改它,結果是不確定的。

不過,如果你丟掉了 常量性尚未 明確聲明爲const對象的,你 可以安全地修改它。

5

如果您開始修改編譯器認爲是const的東西,那麼您正在破壞線程安全的任何機會。

10

亞當說什麼。另一個例子,其中的const_cast會有所幫助:

struct sample { 
    T& getT() { 
     return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    } 

    const T& getT() const { 
     /* possibly much code here */ 
     return t; 
    } 

    T t; 
}; 

我們先加一個const,以種類this點,那麼我們稱之爲getT const版本,然後我們從返回類型,這是有效的,因爲t刪除常量必須是非const的(否則,不可能調用getT的非const版本)。如果你有一個大的函數體,並且你想避免冗餘代碼,這可能非常有用。

32

我可以想到const_cast是安全和有用的兩種情況(可能有其他有效的情況)。

一個是當你有一個常量實例,引用或指針,並且你想傳遞一個指針或引用到一個不是常量正確的API,但是你不會修改該對象。你可以const_cast指針並將它傳遞給API,相信它不會真的改變任何東西。例如:

void log(char* text); // Won't change text -- just const-incorrect 

void my_func(const std::string& message) 
{ 
    log(const_cast<char*>(&message.c_str())); 
} 

另一種是如果你使用的是沒有實現「可變」舊的編譯器,你想創建一個類,在邏輯上是常量,但不按位常量。你可以在const方法中const_cast'this'並修改你的類的成員。

class MyClass 
{ 
    char cached_data[10000]; // should be mutable 
    bool cache_dirty;  // should also be mutable 

    public: 

    char getData(int index) const 
    { 
     if (cache_dirty) 
     { 
      MyClass* thisptr = const_cast<MyClass*>(this); 
      update_cache(thisptr->cached_data); 
     } 
     return cached_data[index]; 
    } 
}; 
7

簡短的回答是否定的,這是不安全的。

長的答案是,如果你知道足夠使用它,那麼它應該是安全的。

當你投射時,你基本上說的是「我知道編譯器不知道的東西。」在const_cast的情況下,你所說的是「即使這個方法需要一個非const引用或指針,我知道它不會改變我傳遞它的參數。」

所以如果你確實知道你在使用演員時聲稱知道什麼,那麼使用它就可以。

-1
#include <iostream> 
using namespace std; 

void f(int* p) { 
    cout << *p << endl; 
} 

int main(void) { 
    const int a = 10; 
    const int* b = &a; 

    // Function f() expects int*, not const int* 
    // f(b); 
    int* c = const_cast<int*>(b); 
    f(c); 

    // Lvalue is const 
    // *b = 20; 

    // Undefined behavior 
    // *c = 30; 

    int a1 = 40; 
    const int* b1 = &a1; 
    int* c1 = const_cast<int*>(b1); 

    // Integer a1, the object referred to by c1, has 
    // not been declared const 
    *c1 = 50; 

    return 0; 
} 

來源:http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_const_cast.htm