使用没有堆内存分配的接口的框架应用程序?

Framework applications using interface without heap memory allocation?

本文关键字:接口 框架 应用程序 分配 内存      更新时间:2023-10-16

我正在尝试为应用程序创建一个框架,以便在我的微处理器中使用。我正在使用Arduino IDE来编译和部署程序。

由于微处理器通常具有低堆内存,因此如果可能,我只想使用堆栈内存。

最小示例:

可以在此处看到整个示例代码。

我将描述我认为最有趣的部分。


iMinEx应用程序(接口(:

class iMinExApplication 
{
public:
virtual void initialize() = 0; // pure virtual
virtual void execute()    = 0; // pure virtual
virtual ~iMinExApplication() = default; // Virtual destructor
};

tMinExApplication(接口的扩展,仅由框架使用(:

class tMinExApplication
{
public:
...
tMinExApplication(iMinExApplication* app, const char name[]) : App(app)
{
strcpy(Name, name);
};
...
void execute()    { App->execute(); };
private:
iMinExApplication* App;
char Name[32]; 
};

tMinEx协调员(主,调用添加的应用程序(

class tMinExCoordinator
{
public:
...
void addApp(iMinExApplication* app, const char name[]) 
{
tMinExApplication* tmpPtr = new tMinExApplication(app, name); // HERE!
Applications[++NumApps] = tmpPtr;
tmpPtr = nullptr;
};
...
void runApps()
{
for (auto& app : Applications) {
// Frequency check
// ...
app->execute();
}
};
private:
tMinExApplication* Applications[];
int NumApps;
};

tMyApp(用户定义的应用,使用继承的接口(

class tMyApp : public iMinExApplication {
...

minExSketch(Arduino IDE sketch(

#include "tMinExClasses.hpp"
#include "tMyApp.hpp"
tMinExCoordinator coordinator{};
tMyApp tmpApp{};
void setup() {
Serial.begin(9600);
coordinator.addApp(&tmpApp, "TEST");
coordinator.initializeApps();
}
void loop() {
coordinator.runApps();
}

以上作品。但是应用程序是在堆内存中分配的,因为它使用关键字new(tMinExCoordinator类定义中的'HERE!',tMinExClasses.hpp中的第 57 行(。

没有它,我似乎无法让它工作。 我可以通过什么其他方式实现这一点,但只在堆栈内存中分配内存?

要求:

  • 堆栈内存分配
  • 将使用
  • 接口。

我有智能指针,但不确定它们是否使用堆内存。另外,我希望最小的例子尽可能干净。

没有

它,我似乎无法让它工作。我可以通过什么其他方式实现这一点,但只在堆栈内存中分配内存?

您可以预先分配一个足够大小的字节数组,然后使用placement-new在该数组中构造对象(请参阅 std::aligned_storage 来帮助您(。 多态性只需要指针/引用在运行时工作,而不是动态分配。

template<std::size_t MaxApps>
class tMinExCoordinator
{
public:
...
tMinExCoordinator()
{
Applications = reinterpret_cast<tMinExApplication*>(appBuffer);
}
~tMinExCoordinator()
{
for (std::size_t i = 0; i < NumApps; ++i)
Applications[i].~tMinExApplication();
}
void addApp(iMinExApplication* app, const char name[]) 
{
if (NumApps >= MaxApps)
throw std::length_error("");
new (&appBuffer[NumApps]) tMinExApplication(app, name);
++NumApps;
}
...
void runApps()
{
for (std::size_t i = 0; i < NumApps; ++i)
{
auto& app = Applications[i];
// Frequency check
// ...
app.execute();
}
}
private:
typename std::aligned_storage<sizeof(tMinExApplication), alignof(tMinExApplication)>::type appBuffer[MaxApps];
tMinExApplication* Applications;
std::size_t NumApps = 0;
};
tMinExCoordinator<1> coordinator{};
...

上面链接的std::aligned_storage文档有一个使用固定内存缓冲区的示例static_vector类,如果向量是在堆栈上构造的,则该缓冲区将位于堆栈上:

#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args) 
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
const T& operator[](std::size_t pos) const 
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data[pos]);
}
// Delete objects from aligned storage
~static_vector() 
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};

您可以在协调器中使用该类,并对其进行一些小的添加,以便它可以与循环一起使用,例如:

template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args) 
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
T& operator[](std::size_t pos)
{
// note: needs std::launder as of C++17
return *reinterpret_cast<T*>(&data[pos]);
}
const T& operator[](std::size_t pos) const 
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data[pos]);
}
std::size_t size() const { return m_size; }
std::size_t capacity() const { return N; }
// iterator access to objects
T* begin()
{
// note: needs std::launder as of C++17
return reinterpret_cast<T*>(&data[0]);
}
T* end()
{
// note: needs std::launder as of C++17
return reinterpret_cast<T*>(&data[m_size]);
}
const T* cbegin() const
{
// note: needs std::launder as of C++17
return reinterpret_cast<const T*>(&data[0]);
}
const T* cend() const
{
// note: needs std::launder as of C++17
return reinterpret_cast<const T*>(&data[m_size]);
}
// Delete objects from aligned storage
~static_vector() 
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};
template<std::size_t MaxApps>
class tMinExCoordinator
{
public:
...
void addApp(iMinExApplication* app, const char name[]) 
{
Applications.emplace_back(app, name);
}
...
void runApps()
{
for (auto& app : Applications)
{
// Frequency check
// ...
app.execute();
}
}
private:
static_vector<tMinExApplication, MaxApps> Applications;
};

我有智能指针,但不确定它们是否使用堆内存。

默认情况下,它们依赖于newdelete,因此依赖于动态内存。 但是,如果您还为他们提供不会释放该内存的自定义删除程序,则可以为它们提供堆栈内存的指针。