释放内存后使用布局new c++

bttbmeg0  于 2023-01-03  发布在  其他
关注(0)|答案(1)|浏览(203)

我试图解决在对ESP8266 MCU进行编程时遇到的一个问题,我基本上需要将一个对象声明为全局对象,这样它就不会在用户发送HTTP请求时导致其中一个库的回调问题。但是我也需要等到从EEPROM中获得一些数据之后才能调用构造函数,因此很多人告诉我应该使用placement new这对我想做的事情非常有效。但我还是不明白:在调用了对象的构造函数之后,因为它是全局声明的,我试图保留它,我不应该通过调用析构函数来删除它,而是应该删除我用来保存对象的第一个指针吗(我不完全确定我的措辞是否正确)?

class display{
    public:
    display(int b){
        std::cout<<"the value of a: "<<b;
    }
};

char *memory= new char[sizeof(display)];
display *obj;

int main(){
    int a=69;
    obj=new(memory) display(a);

    return 0;
}

这或多或少是我在ESP代码中所做的(没有所有其他的东西,但就我试图对placement new所做的而言是相同的)。我的问题是,在有人做了这样的事情后,如果我删除 * 内存会导致问题吗?

l3zydbqr

l3zydbqr1#

这里不需要分配new,你只需要确保你有一个足够大小和对齐的数组:

alignas(display) std::byte memory[sizeof(display)];
display *obj = nullptr;

(您可以使用unsigned char代替std::byte,但我认为自C++17起就可用的std::byte更好地表达了原始内存存储的意图。)
然后使用以下内容构造对象

obj = new(memory) display(a);

当不再需要它时,显式调用它的析构函数:

obj->~display();

在这种情况下不需要delete。使用您的方法,在析构函数调用之后需要 * 额外的 * delete[] memory;来释放由第一个new分配的内存。如果在析构函数调用后不打算重用它(例如,您可以在循环中使用placement-new构造新的display)。注意你需要在obj上调用析构函数,在memory上调用delete[]。这是不可互换的。memory是指向分配的内存块的指针,obj是指向嵌套在内存块中的对象的指针。前者是通过分配new[]来分配的,因此需要delete[],而后者只通过(非分配)placement-new来创建,因此只需要显式析构函数调用。
当然,您可以考虑是否真的需要析构函数调用,如果display不包含任何需要清理的资源,那么您可以跳过它,尽管我还是会安全地调用它,以防display稍后被更改。
此外,C++17起的标准库将所有这些实现为std::optional。如果你可以使用它,那么就这样做:

std::optional<display> obj;
// obj is now empty, can be tested with `if(obj)`

obj.emplace(/* constructor arguments */);
// obj now contains a display that can be accessed like a pointer with * and ->

// destructor of obj will take care of correctly destroying the display

emplace也可以被多次调用来用新的display替换display(并调用旧的析构函数),或者.reset()可以被用来显式清空optional
如果你没有C++17可用,std::unique_ptr可以用类似的方式使用,除了它将使用堆分配,而std::optional没有,而且即使display是可复制的,std::unique_ptr也是不可复制的,而std::optional可以。

std::optional<display> obj;
// obj is now empty, can be tested with `if(obj)`

obj = std::make_unique<display>(/* constructor arguments */);
// obj now contains a display that can be accessed like a pointer with * and ->

// destructor of obj will take care of correctly destroying the display

obj也可以以这种方式被重新分配多次,或者用= nullptr;.reset()重置,并且在任一情况下,它都将负责正确地销毁任何display,就像std::optional所做的那样。

相关问题