[英]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字符串),並將其作為指向字符數組的指針返回。
會自動附加一個終止的空字符。
返回的數組指向內部位置,該位置具有此字符序列所需的存儲空間及其終止的空字符,但是此數組中的值不應在程序中進行修改,只能保證在下一次調用時保持不變。字符串對象的非恆定成員函數。”
是的,它將帶來危險,因為
input
指向現在恰好是c_str
任何內容,但是如果some_text
更改或消失,您將獲得指向垃圾的指針。 只要不改變字符串,就保證c_str
的值是有效的。 並且甚至正式地,僅當您也不要在其他字符串上調用c_str()
時。 *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.