簡體   English   中英

C ++:將整數強制轉換為指針的安全方法

[英]C++: Safe way to cast an integer to a pointer

我需要將包含地址的整數類型轉換為實際的指針類型。 我可以按如下方式使用reinterpret_cast:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

但是,這不會執行任何運行時檢查,以查看所討論的地址是否實際包含MyClass對象。 我想知道首先轉換為void *(使用reinterpret_cast),然后對結果使用dynamic_cast是否有任何好處。 像這樣:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

使用第二種方法有什么優勢嗎?

不,這樣做沒有特定的優勢。 當您使用reinterpret_cast ,所有賭注都關閉了。 由您確定轉換是否有效。

實際上沒有嚴重的優勢。 如果void *指向不是多態對象的指針的對象,則您會立即遇到未定義的行為(通常是訪問沖突)。

dynamic_cast類型檢查由不同的C ++實現以不同的方式實現; 如果您想為特定的實現提供答案,則應提及您正在使用的實現。 通常,回答該問題的唯一方法是參考ISO標准C ++。

根據我對標准的閱讀,在void指針上調用dynamic_cast是非法的:

dynamic_cast<T>(v)

“如果T是指針類型,則v將是完成類類型的指針的右值”

(來自ISO C ++標准的5.2.7.2)。 void不是完整的類類型,因此該表達式是非法的。

有趣的是,被強制轉換為的類型可以是空指針,即

void * foo = dynamic_cast<void *>(some_pointer);

在這種情況下, dynamic_cast總是成功,並且結果值是v指向最派生對象的指針。

安全的方法是保留所有活動的MyClass對象的記錄。 最好將此記錄保存在std::set<void*> ,這意味着您可以輕松地添加,刪除和測試元素。

將它們存儲為void*的原因是,您不會像從整數創建未對齊的MyClass*指針那樣冒着麻煩。

  • 首先,將int “重新解釋”為void *是一個壞主意。 如果sizeof(int)為4, sizeof(void *)為8(64x系統),則格式錯誤。

  • 此外, dynamic_cast僅對多態類有效。

如果可以肯定地知道the_integer指向一個已知的基類(具有至少一個虛擬成員),則實際上可能會有一個好處:知道對象是特定的派生類。 但是您必須先將reinterpret_cast為您的基類,然后再進行dynamic_cast

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

dynamic_cast使用void*是沒有用的,並且完全是錯誤的。 您不能使用dynamic_cast來檢查內存中任意位置上是否存在有效對象。

在非指針類型變量中存儲地址時,也應注意。 有一些體系結構,其中sizeof(void *)!= sizeof(int),例如LP64。

選項1是您唯一的(半)便攜式/有效選項。

選項2:作為dynamic_cast無效的C ++(因為不允許void)。

在實現級別,它需要來自源類型的類型信息才能到達目標類型。 無法(或可能無法)從void *獲取運行時源類型信息,因此這也是無效的。

Dynamic_Cast用於提升和降低類型層次結構,而不是未知類型。

附帶說明一下,您可能應該使用void *而不是整數來存儲無類型的指針。 一個int的大小可能不足以存儲指針。

在C ++中處理指針的最安全方法是處理類型安全的指針。 這意味着:

  • 切勿將指針存儲在指針以外的任何其他位置
  • 避免空指針
  • 永遠不要將指針傳遞給其他進程
  • 如果您打算在線程上使用指針,請考慮weak_ptr

原因是:您打算做的事是不安全的,可以避免,除非您與不安全的(舊版)代碼交互。 在這種情況下,請考慮MSalters的答案,但請注意,這仍然很麻煩。

暫無
暫無

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

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