Som*_*guy 0 c++ arduino-esp8266
我试图解决在编程 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;
}
Run Code Online (Sandbox Code Playgroud)
这或多或少是我在 ESP 代码中所做的事情(没有所有其他内容,但就我尝试对新的放置所做的事情而言是相同的)。我的问题是,在有人做了类似的事情之后,如果我删除*内存会导致问题还是没有必要?
这里不需要分配new。您只需要确保有一个足够大小和对齐的数组:
alignas(display) std::byte memory[sizeof(display)];
display *obj = nullptr;
Run Code Online (Sandbox Code Playgroud)
(std::byte您可以使用unsigned char,但我认为std::byte,自 C++17 起可用,可以更好地表达原始内存存储的意图。)
然后构造对象
obj = new(memory) display(a);
Run Code Online (Sandbox Code Playgroud)
当不再需要它时,显式调用它的析构函数:
obj->~display();
Run Code Online (Sandbox Code Playgroud)
在这种情况下不需要delete。根据您的方法,如果您不打算在析构函数调用之后重用它,则在析构函数调用之后需要额外的内存来释放第一个分配的内存(您可以 在循环中使用placement-new构造一个新的内存来执行此操作))。请注意,您需要调用 on和on的析构函数。这是不可互换的。是指向分配的内存块的指针和指向嵌套在其中的对象的指针。前者是通过 allocate 进行分配的,因此是必需的,而后者仅是通过(非分配的)placement-new 创建的,因此只需要显式的析构函数调用。delete[] memory;newdisplayobjdelete[]memorymemoryobjnew[]delete[]
当然,你可以考虑是否真的需要析构函数调用。如果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
Run Code Online (Sandbox Code Playgroud)
emplace也可以多次调用以用display新的替换(并调用旧的析构函数),或者.reset()可以用于显式清空optional.
如果您没有可用的 C++17,则std::unique_ptr可以以类似的方式使用 a,只不过它将使用堆 allcoation,但std::optional它不会,并且std::unique_ptr即使是也不可复制display,而 whilestd::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
Run Code Online (Sandbox Code Playgroud)
obj也可以以这种方式重新分配多次,或者用= nullptr;或重置.reset(),在任何一种情况下,它都会display像这样std::optional做一样正确地销毁任何东西。