我有一个用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 =新的SPI(P0_9,P0_8,P0_7);
?
答案 0 :(得分:1)
析构函数只是具有特殊名称的函数。像实例一样调用它。〜T()。
void destroy()
{
SPI_Master.~SPI():
}
您可以通过新放置位置在给定位置强制构造对象。
void reinit()
{
new(&SPI_Master) SPI(/*arguments go here*/);
}
答案 1 :(得分:0)
详细说明SPD的提示:
2)显式调用析构函数,并使用new放置在同一内存地址中构建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()
请注意:
全局实例有其局限性,但是它可能存在,并且出于任何原因都不能更改。 (对于单身人士,应提及Singleton Pattern,这有助于解决static initialization order ‘fiasco’ (problem)?。)
通常,由new
创建的东西通常会构造到分配给堆的内存中(即,如果未使用自定义new
),这与在其他地方创建的静态实例相反。 / p>
Placement new
可以进行构造而无需分配,即不存储到调用方提供的存储中,即与存储的分配方式无关。
答案 2 :(得分:0)
SPI SPI_Master(P0_9, P0_8, P0_7);
与...不同
SPI SPI_Master = new SPI(P0_9, P0_8, P0_7);
最后一行将不编译,只要new
返回指向堆对象(而非对象)中的指针。同时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)销毁期间的销毁和建造订单,将产生您的编译器: -创建新的,删除旧的并分配新的 -删除旧的,创建新的,分配新的
因此,此解决方案可能非常危险。