我试图解决在对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所做的而言是相同的)。我的问题是,在有人做了这样的事情后,如果我删除 * 内存会导致问题吗?
1条答案
按热度按时间l3zydbqr1#
这里不需要分配
new
,你只需要确保你有一个足够大小和对齐的数组:(您可以使用
unsigned char
代替std::byte
,但我认为自C++17起就可用的std::byte
更好地表达了原始内存存储的意图。)然后使用以下内容构造对象
当不再需要它时,显式调用它的析构函数:
在这种情况下不需要
delete
。使用您的方法,在析构函数调用之后需要 * 额外的 *delete[] memory;
来释放由第一个new
分配的内存。如果在析构函数调用后不打算重用它(例如,您可以在循环中使用placement-new构造新的display
)。注意你需要在obj
上调用析构函数,在memory
上调用delete[]
。这是不可互换的。memory
是指向分配的内存块的指针,obj
是指向嵌套在内存块中的对象的指针。前者是通过分配new[]
来分配的,因此需要delete[]
,而后者只通过(非分配)placement-new来创建,因此只需要显式析构函数调用。当然,您可以考虑是否真的需要析构函数调用,如果
display
不包含任何需要清理的资源,那么您可以跳过它,尽管我还是会安全地调用它,以防display
稍后被更改。此外,C++17起的标准库将所有这些实现为
std::optional
。如果你可以使用它,那么就这样做:emplace
也可以被多次调用来用新的display
替换display
(并调用旧的析构函数),或者.reset()
可以被用来显式清空optional
。如果你没有C++17可用,
std::unique_ptr
可以用类似的方式使用,除了它将使用堆分配,而std::optional
没有,而且即使display
是可复制的,std::unique_ptr
也是不可复制的,而std::optional
可以。obj
也可以以这种方式被重新分配多次,或者用= nullptr;
或.reset()
重置,并且在任一情况下,它都将负责正确地销毁任何display
,就像std::optional
所做的那样。