簡體   English   中英

C ++ const強制轉換,不確定這是否安全

[英]C++ const cast, unsure if this is secure

這似乎是一個愚蠢的問題,但我確實需要澄清一下:

這會給我的程序帶來危險嗎?

甚至需要const_cast嗎?

如果我更改輸入指針的值,它將與std::string安全地一起工作還是會產生未定義的行為?

到目前為止,唯一需要擔心的是,每當我修改輸入指針並使它不可用時,這可能會影響字符串“ some_text”。

std::string some_text = "Text with some input";

char * input = const_cast<char*>(some_text.c_str());

感謝您給我一些提示,我想避免用自己的腳射擊

舉一個邪惡行為的例子:與gcc的“寫時復制”實現的交互。

#include <string>
#include <iostream>

int main() {
    std::string const original = "Hello, World!";
    std::string copy = original;

    char* c = const_cast<char*>(copy.c_str());
    c[0] = 'J';

    std::cout << original << "\n";
}

在行動對ideone

Jello,世界!

問題 ? 顧名思義,gcc的std::string的實現使用了一個帶有引用計數的共享緩沖區。 修改字符串后,實現會立即檢查緩沖區是否已共享,如果共享,則在修改緩沖區之前先對其進行復制,以確保共享此緩沖區的其他字符串不受新寫操作的影響(因此名稱,復制時寫)。

現在,使用您的邪惡程序,您可以通過const方法訪問共享緩沖區(承諾不進行任何修改),但是您必須對其進行修改!

請注意,使用MSVC的實現(不使用寫時復制),其行為將有所不同(將正確打印"Hello, World!" )。

這恰恰是未定義行為的本質。

通過使用const_cast拋棄其const來修改固有的const對象是Undefined Behavior

string :: c_str()返回const char * ,即:指向常量c樣式字符串的指針。 從技術上講,修改此選項將導致未定義的行為。

請注意,當您有一個指向非const數據的const指針並且希望修改非恆定數據時,可以使用const_cast

簡單地進行轉換不會帶來不確定的行為。 但是,將修改指向的數據。 另請參見ISO 14882:98 5.2.7-7 )。

如果您想要一個指向可修改數據的指針,則可以使用

std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];

std::string在內部管理它自己的內存,這就是為什么它像c_str()函數一樣直接返回指向該內存的指針的原因。 它確保它是恆定的,以便您嘗試對其進行修改時,編譯器將向您發出警告。

以這種方式使用const_cast實際上會放棄這種安全性,並且如果您絕對確定不會修改內存,那么這只是可以接受的實踐。

如果不能保證,則必須復制字符串並使用副本。 在任何情況下執行此操作當然都非常安全(可以使用strcpy )。

請參閱C ++參考網站:

const char* c_str ( ) const;

“生成與字符串對象具有相同內容的空終止字符序列(c字符串),並將其作為指向字符數組的指針返回。

會自動附加一個終止的空字符。

返回的數組指向內部位置,該位置具有此字符序列所需的存儲空間及其終止的空字符,但是此數組中的值不應在程序中進行修改,只能保證在下一次調用時保持不變。字符串對象的非恆定成員函數。”

是的,它將帶來危險,因為

  1. input指向現在恰好是c_str任何內容,但是如果some_text更改或消失,您將獲得指向垃圾的指針。 只要不改變字符串,就保證c_str的值是有效的。 並且甚至正式地,僅當您也不要在其他字符串上調用c_str()時。
  2. 為什么需要丟棄const? 您不打算寫*input ,對嗎? 那是禁忌!

這是一件非常不好的事情。 看看std :: string :: c_str() 做什么,並同意我的看法。

其次,考慮為什么要對std :: string的內部進行非常量訪問。 顯然您想修改內容,因為否則您將使用const char指針。 另外,您擔心您不想更改原始字符串。 為什么不寫

std::string input( some_text );

然后您就有了一個std :: string,可以在不影響原始字符的情況下進行處理,並且擁有std :: string功能,而不必使用原始的C ++指針。

另一個旋轉是它使代碼極難維護。 舉例:幾年前,我不得不重構一些包含長函數的代碼。 作者已經編寫了函數簽名以接受const參數,但隨后在函數中const_cast它們以刪除constness。 這破壞了函數所提供的隱含保證,並使得很難知道代碼其余部分中參數是否已更改。

簡而言之,如果您可以控制字符串,並且認為需要更改它,則首先使其成為非常量。 如果您不這樣做,那么您將必須復制一份並進行處理。

它是UB。 例如,您可以執行以下操作:

size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];

沒有任何類型的轉換,並且編譯器將不會報告錯誤。 但是此代碼是非法的。 士氣是每次都需要考慮采取行動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM