簡體   English   中英

使用new char []或malloc的結果來表示浮動*是UB(嚴格別名沖突)嗎?

[英]Is using the result of new char[] or malloc to casted float * is UB (strict aliasing violation)?

哪些代碼有UB(具體來說,哪些違反了嚴格的別名規則)?

void a() {
    std::vector<char> v(sizeof(float));
    float *f = reinterpret_cast<float *>(v.data());
    *f = 42;
}

void b() {
    char *a = new char[sizeof(float)];
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void c() {
    char *a = new char[sizeof(float)];
    float *f = new(a) float;
    *f = 42;
}

void d() {
    char *a = (char*)malloc(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void e() {
    char *a = (char*)operator new(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

我問這個,因為這個問題。

我認為, d沒有UB(否則malloc在C ++中沒用)。 因此,似乎合乎邏輯, bce也沒有。 我錯了嗎? 也許b是UB,但c不是?

序言: 存儲對象是C ++中的不同概念。 存儲是指存儲空間, 對象是具有生命周期的實體,可以在一個存儲區中創建和銷毀。 隨着時間的推移,存儲可以重新用於托管多個對象。 所有對象都需要存儲,但可以存儲沒有對象的存儲。


c是對的。 Placement-new是在存儲中創建對象的有效方法之一(C ++ 14 [intro.object] / 1),即使該存儲中存在預先存在的對象。 重新使用存儲會隱藏地破壞舊對象,只要它們沒有非平凡的析構函數([basic.life] / 4),這就完全沒問題了。 new(a) float; 在現有存儲([expr.new] / 1)中創建float類型和動態存儲持續時間的對象。

de在當前對象模型規則中由於省略而未定義:通過glvalue表達式訪問內存的效果僅在表達式引用對象時定義; 而不是當表達式引用不包含任何對象的存儲時。 (注意:請不要對現有定義明顯不足的問題留下非建設性意見)。

這並不意味着“malloc無用”; mallocoperator new是獲得存儲 然后,您可以在存儲中創建對象並使用這些對象。 事實上,這正是標准分配器和new表達式的工作原理。

ab是嚴格的別名沖突: float類型的glvalue用於訪問不兼容類型char對象。 ([basic.lval] / 10)


有一種建議這將使所有的明確定義的情況下(比下面提到對准其他):下該提案中,使用*f隱式地創建該類型中的位置的目的,用一些注意事項。


注意:在be的情況下沒有對齊問題,因為new-expression和::operator new保證為任何類型([new.delete.single] / 1)正確地分配存儲。

但是,在std::vector<char>的情況下,即使標准指定調用::operator new來獲取存儲,標准也不要求將第一個向量元素放在該存儲的第一個字節中; 例如,向量可以決定在前面分配3個額外字節,並將其用於某些簿記。

雖然OP和我之間的討論產生了這個問題,但我仍然會在這里解釋。

我相信所有這些對c()保存包含嚴格的別名違規,正如標准正式定義的那樣。

我的基礎是標准的第1.8.1節

...對象由定義(3.1),new-expression(5.3.4)或實現(12.2)在需要時創建。 ...

reinterpret_cast<>內存不屬於這兩種情況。

cppreference

鍵入別名

每當嘗試通過類型為AliasedType的glvalue讀取或修改DynamicType類型的對象的存儲值時,除非滿足下列條件之一,否則行為是未定義的:

  • AliasedType和DynamicType類似。
  • AliasedType是DynamicType的(可能是cv限定的)有符號或無符號變體。
  • AliasedType是std :: byte,(自C ++ 17開始)char或unsigned char:這允許將任何對象的對象表示檢查為字節數組。

非正式地,如果在每個級別剝離cv資格(但排除函數類型內的任何內容)之后,兩種類型是相似的,它們是相同的類型。

例如:[......一些例子......]

也是cppreference

glvalue是一個表達式,其評估決定了對象,位域或函數的身份;

除了(c)之外,上述內容與所有示例相關。 類型既不相似也不簽名/無符號變體。 AliasedType (您AliasedType為的類型)既不是charunsigned charstd::byte 因此,所有這些(但是c)都表現出不確定的行為。

免責聲明:首先,cppreference不是官方參考,但只有標准是。 其次,不幸的是,如果我對cppreference上讀到的內容的解釋是正確的,我甚至不能100%肯定。

暫無
暫無

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

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