如何强制调用类的全局实例的析构函数和构造函数(以便"re-init"类实例)



我有一个在C 中开发的固件项目,所有驱动程序都是用类制成的,并且没有简单的修改方法。

驱动程序用于UP的内部外围,并由该类的全球实例实现;现在,我必须修改该功能,并在异常情况下允许驱动程序的"重新启动"。

驱动程序的初始化是在驱动程序的构造函数中进行的(以这种方式实现,我无法修改(,并且没有明确的方法(一种特定的方法或类似方法(重新调用该功能。因此,我需要强迫回忆班的构造师。丢失实例的所有信息不是问题,因此可以删除实例并重新重新进行。

例如,代码的一部分类似于(来自MBED库(:

class SPI {
public:
    SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel=NC);
    void format(int bits, int mode = 0);
[.....]
  ~SPI()
}

在代码的其他部分中,有一个全局实例:

SPI SPI_Master(P0_9, P0_8, P0_7);
void funcA(int b){
}

因此,在函数中有一种方法可以做类似的事情:

void SPIException(){
   delete SPI_Master;
   SPI_Master = new SPI (P0_9, P0_8, P0_7);
}

所以要迫使构造函数被召回?

和一点澄清:

spi spi_master(p0_9,p0_8,p0_7(;

与:

完全相同

spi spi_master = new spi(p0_9,p0_8,p0_7(;

destructor只是具有特殊名称的函数。称其为实例。〜t((。

void destroy()
{
  SPI_Master.~SPI():
}

您可以通过新的位置在给定的位置强行构造一个对象。

void reinit()
{
  new(&SPI_Master) SPI(/*arguments go here*/);
}

SPI SPI_Master(P0_9, P0_8, P0_7);SPI SPI_Master = new SPI(P0_9, P0_8, P0_7);

new将指针返回到Heap对象中的指针时,最后一行不会被编译,而不是对象。同时,SPI SPI_Master(P0_9, P0_8, P0_7);位于堆栈中。您可以阅读有关内存类型的其他信息。正确的表格将是: SPI * SPI_Master = new SPI(P0_9, P0_8, P0_7);是的,这是您可以使用的解决方案之一。

,您提到的功能后的某个地方将按预期工作:

void SPIException(){
   delete SPI_Master;
   SPI_Master = new SPI (P0_9, P0_8, P0_7);
}

但它将调用使用SPI_MASTER的所有代码的更改:从SPI_Master.anyCall()SPI_Master->anyCall()

如果您无法更改行: SPI SPI_Master(P0_9, P0_8, P0_7);

您可以尝试明确调用驱动器,而不是覆盖相同的变量:

SPI_Master.~SPI(); 
SPI_Master = SPI(P0_9, P0_8, P0_7);

但是要小心:1(这取决于构造函数和破坏者的身体真正是什么。2(将产生您的组合商的销毁和建设顺序: - 创建新的,删除旧并分配新 - 删除旧,创建新,分配新

因此,此解决方案可能很危险。

使用global 指针与spi_master。这样:

SPI* SPI_Master;
// in some init code:
SPI_Master = new SPI .....

然后您的spiexception可以按书面形式使用。

详细说明SPD的提示:

2(显式调用破坏者并使用新的位置,以在同一内存地址构建SPI

我做了一个小样本:

#include <iostream>
struct Global {
  int a1, a2;
  Global(int a1, int a2): a1(a1), a2(a2)
  {
    std::cout << "Global::Global(): a1: " << a1 << " a2: " << a2 << 'n';
  }
  ~Global()
  {
    std::cout << "Global::~Global()n";
  }
  Global(const Global&) = delete;
  Global& operator=(const Global&) = delete;
};
std::ostream& operator<<(std::ostream &out, const Global &global)
{
  return out
    << "&global: " << &global << 'n'
    << "global: global.a1: " << global.a1 << " global.a2: " << global.a2 << 'n';
}
Global global(123, 456);
int main()
{
  std::cout << "Initially: " << global;
  global.a1 = 321; global.a2 = 654;
  std::cout << "Changed: " << global;
  global.~Global();
  new(&global) Global(123, 456);
  std::cout << "Re-Inited: " << global;
  std::cout << "Exiting...n";
}

输出:

Global::Global(): a1: 123 a2: 456
Initially: &global: 0x6013d8
global: global.a1: 123 global.a2: 456
Changed: &global: 0x6013d8
global: global.a1: 321 global.a2: 654
Global::~Global()
Global::Global(): a1: 123 a2: 456
Re-Inited: &global: 0x6013d8
global: global.a1: 123 global.a2: 456
Exiting...
Global::~Global()

coliru

实时演示

请注意:

全局实例有其局限性,但可能存在,并且由于任何原因可能不会更改。(对于单例,应提及单身图案,还有其他帮助解决静态初始化顺序"惨败"(问题(?(

通常,new创建的东西通常是在分配在堆上的内存中(即,如果不使用自定义new(,这与在其他地方创建的静态实例相反。

放置new可以在没有分配的情况下进行施工,即呼叫者提供的存储空间,即独立于分配存储。

相关内容

最新更新