簡體   English   中英

在非指針變量和 class 成員上放置新的

[英]Placement new on non-pointer variables and class members

考慮以下示例:

#include <iostream>

struct A {

    int i;

    A(int i)
    {
        this->i = i;
    }

    A &operator=(const A &a) = delete;
    A(const A &a) = delete;
};

int main()
{
    A a(1);
    new(&a) A(5);
    //a = A(7); // not allowed since = is deleted in A
    std::cout << a.i << std::endl;
}

這是一個使用placement new 運算符的簡單示例。 由於struct A的復制構造函數和賦值運算符已被刪除(無論出於何種原因),因此無法更改變量A a持有的 object,除非將其地址傳遞給放置 new 運算符。

造成這種情況的原因可能包括struct A包含較大的 arrays(例如 100M 條目),必須在賦值運算符和復制構造函數中進行復制。

問題的第一部分圍繞這種方法的“合法性”。 我發現了這個stackoverflow問題,接受的答案是

這是完全合法的。 而且沒用,因為您不能使用 var [ A a in this case] 來引用您在放置 new 后存儲在其中的 [object] 的 state。 任何此類訪問都是未定義的行為。 [...] 在任何情況下,您都不能在將 new 放在 var 上之后再引用它。

為什么會這樣? 我已經看到了placement new 運算符的其他幾個示例,它們總是類似於

A a(1);
A *b = new(&a) A(2);
// Now use *b instead of a

據我了解,使用A aA *b訪問 object 應該無關緊要,因為放置 new 替換了A a地址處的 object ,這當然A a 也就是說,我希望總是b == &a 也許答案不夠清楚,這個限制是由於 class 成員的 const-ness 造成的。

這是另一個具有相同想法的示例,但是這次struct A被嵌入到另一個 object 中:

#include <iostream>

struct A {

    int *p;

    A(int i)
    {
        p = new int(i);
    }

    ~A()
    {
        delete p;
    }

    A &operator=(const A &a) = delete;
    A(const A &a) = delete;
};

struct B {

    A a;

    B(int i) : a(i)
    {
    }

    void set(int i)
    {
        a.~A(); // Destroy the old object
        new(&a) A(i);
    } 

};

int main()
{
    B b(1);
    b.set(2);
    std::cout << *(b.a.i) << std::endl;
    // This should print 2 and there should be no memory leaks
}

問題基本相同,推理相同。 將placement-new放入地址&a是否有效?

對於這個特定的代碼,您可以使用a來指代您放置的新 object。 [basic.life]/8涵蓋了這一點

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • 新 object 的存儲恰好覆蓋了原始 object 占用的存儲位置,並且

  • 新的 object 與原始 object 的類型相同(忽略頂級 cv 限定符),並且

  • 原始 object 的類型不是 const 限定的,並且,如果 class 類型不包含任何類型為 const 限定或引用類型的非靜態數據成員,並且

  • 原始的 object 和新的 object 都不是可能重疊的子對象([intro.object])。

強調我的

您檢查所有這些要求,因此a將引用您放置在a的 memory 中的“新” A

暫無
暫無

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

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