2011-12-18 23 views
5

根據嚴格別名規則:字符*轉換和重疊規則

struct B { virtual ~B() {} }; 
struct D : public B { }; 

D d; 
char *c = reinterpret_cast<char*>(&d); 

char*一個不同類型的任何對象是有效的。但現在的問題是,它是否會指向& d的相同地址? C++ Standard保證它會返回相同的地址是什麼?

+9

我認爲你的析構函數是錯誤的 – 2011-12-18 22:04:22

+4

我不知道答案。但是,這種知識何時會在實踐中有用呢? – 2011-12-18 22:06:46

+0

好問題。一些演員可以改變地址(例如,當涉及多重繼承時)。我想知道是不是這種情況。 – Kos 2011-12-18 22:11:11

回答

6

c&d確實具有相同的值,並且如果您重新解釋c返回到D*,您將得到一個有效的指針,您可以解除引用。此外,你可以將c作爲(指向第一個元素的指針)一個不透明數組char[sizeof(D)] - 這確實是指向char指針的指針的主要目的:允許(反)序列化(例如ofile.write(c, sizeof(D));),儘管通常只應用基本類型(及其陣列)做到這一點,因爲化合物的類型的二進制佈局沒有在便攜式方式通常指定。

正如@Oli正確指出並希望我強化一樣,您應該永遠不要將化合物類型作爲整體進行序列化。結果幾乎不會被反序列化,因爲數據字段之間的多態類和填充的實現沒有被指定,並且您無法訪問。

注意reinterpret_cast<char*>(static_cast<B*>(&d))可以通過類似的推理不透明陣列char[sizeof(B)]進行處理。

+0

我想也許你應該更清楚一點,序列化/反序列化這樣的非POD類(即使用vptrs的類)是非常糟糕的主意。 – 2011-12-19 00:03:04

+0

@OliCharlesworth:嗯,*對象*沒有任何隱藏的「vptrs」......這只是在類實現中。對象應該仍然具有相當「正常」的佈局,至少在進入虛擬繼承之前......通常的填充問題是一個更直接的原因,而不是以「天真」的方式來序列化類類型(雖然然後可能再次出現沒問題的情況下,例如使用內存映射網絡I/O的相同機器的HPC集羣...)。買方當心:-) – 2011-12-19 00:11:13

+0

什麼?虛函數的存在意味着類實例必須有一個vptr(好吧,在任何典型的實現中)。 – 2011-12-19 00:12:28

2

5.2.10節,2003年C++標準的點7表示:

一個指針,一個對象可以被顯式轉換爲一個指針到不同類型的 對象。除了將類型爲 的「指針指向T1」的右值轉換爲類型「指向T2的指針」(其中T1和T2是 對象類型,並且其中T2的對齊要求不是 比T1更嚴格)和返回其原始類型產生 原始指針值,這樣的指針轉換的結果是未指定的 。

如果用「相同地址」表示「原始指針值」,則該條目表示「是」。

0

的意圖是明顯的(而不是一些需要進行辯論):

reinterpret_cast永不改變的地址的值,除非目標類型不能代表所有地址值(像一個小的整數類型,在具有內部對齊的指針類型上:f.ex.只能表示偶數地址的指針,或者指向對象和指向函數的指針不能被混合......)。

該標準的措辭未能捕捉到,但這並不意味着這裏存在真正的實際問題。

char *c = reinterpret_cast<char*>(&d); 

c將指向d第一個字節,始終。