[英]Class using virtual inheritance seems to allow a base class constructor to overwrite another base class' members
我對包含虛擬基礎的對象的內存布局不太熟悉,無法理解為什么clang和gcc都會錯誤地編譯以下內容。 這是一個學術練習,所以請原諒構造函數中的memset()
的輕浮。 我正在測試使用Linux x86-64同時使用clang 7和gcc 8.2:
#include <cstring>
struct A {
A() { memset(this, 0, sizeof(A)); }
int i;
char a;
};
struct B { char b = 'b'; };
struct C : virtual B, A {};
char foo() {
C c;
return c.b;
}
使用-O2 -Wall -pedantic -std=c++17
進行編譯時,兩個編譯器都會生成以下程序集而不顯示警告:
foo():
xor eax, eax
ret
將C
更改為不進行虛擬繼承B
或在調用memset時將sizeof(A)
更改為5
或更小都會將編譯器的輸出更改為返回'b'
,正如我所期望的那樣:
foo():
mov al, 98 # gcc uses eax directly, here
ret
當它從B
虛擬/非虛擬派生時, C
的內存布局是什么?這些編譯器是否錯誤,允許A
的構造函數將不同基類的成員清零? 我知道布局不是由標准定義的,但我希望所有實現都能確保類的構造函數不會干擾不相關類的數據成員,即使在像這樣的多重繼承中使用時也是如此。 或者至少警告這樣的事情可能會發生。 (這里沒有診斷出gcc的新-Wclass-memaccess
警告)。
如果歸結為memset(this, 0, sizeof(A))
在構造函數中無效,那么我希望編譯器無法編譯或至少警告。
鏈接: https : //godbolt.org/z/OSQV1j
我對包含虛擬基礎的對象的內存布局不夠熟悉
虛擬基礎(以及具有虛擬基礎的基類子對象)通常不構造,也不像相同類型的完整對象那樣表示 ,而不是具有相同布局的任何其他子對象(該基類子對象的每個子對象的相對位置) )作為具有相同類型的完整對象:
這些都是構造和表示為完整的對象。
澄清:雖然基類子對象的構造函數通常與完整對象的構造函數相同, 但專門保留給基類子對象的內存可能小於其正常大小 。
理解為什么clang和gcc都會錯誤地編譯以下內容。
您尚未發布任何代碼生成錯誤的證據。
這是一個學術練習,請原諒輕浮
這不是輕浮的, 顯然是錯的 。
memset()
在復制構造函數中。
這樣做會通過覆蓋它來破壞對象。
代碼使用不受支持的操作(在構造期間覆蓋c2
對象的內存), 並且編譯器沒有警告您 ,您的代碼使用通過調用低級別內存訪問函數( memset
)來終止其生命周期的對象。 結束基類構造函數中的生命周期是非法的:從技術上講,當你結束它時,生命周期甚至都沒有開始。
如果要通過覆蓋來終止對象的生命周期,請在構造之后執行。
摘要:
不能保證T
類型的每個子對象都“擁有” sizeof (T)
字節並且可以覆蓋那些; 但是,對於數組元素和成員,這是有保證的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.