使用没有堆内存分配的接口的框架应用程序?
Framework applications using interface without heap memory allocation?
我正在尝试为要在我的微处理器中使用的应用程序创建一个框架。我正在使用 Arduino IDE 来编译和部署程序。
由于微处理器的堆内存通常较低,因此我想尽可能只使用堆栈内存。
最小示例:
完整示例代码可见here.
我会描述我认为最有趣的部分。
iMinExApplication(接口):
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];
};
tMinExCoordinator(master,调用添加的应用)
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 草图)
#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
('HERE!'
在 tMinExCoordinator
class 定义中,第 57 行在 tMinExClasses.hpp).
没有它我似乎无法让它工作。
除了在堆栈内存中分配内存外,我还可以通过其他什么方式实现它?
要求:
- 堆栈内存分配
- 要使用的接口
我知道智能指针,但不确定它们是否使用堆内存。另外,我希望最小示例尽可能简洁。
I cannot seem to get it to work without it. In what other way could I implement this, but only allocating memory in stack memory?*
您可以预先分配一个足够大小的字节数组,然后使用 placement-new
to construct objects inside of that array (see std::aligned_storage 来帮助您。)多态性只需要 pointers/references 在运行时工作,不需要动态分配。
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
class 使用固定的内存缓冲区,如果在堆栈上构建向量,它将在堆栈上:
#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();
}
}
};
您可以在协调器中使用 class,并对其进行一些小的添加,以便它可以与循环一起使用,例如:
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;
};
I have though of smart pointers, but am unsure if they use heap memory or not.
默认情况下,它们依赖于 new
和 delete
,因此是动态内存。但是,您 可以 为它们提供指向堆栈内存的指针,如果您还为它们提供不会释放该内存的自定义删除器。
我正在尝试为要在我的微处理器中使用的应用程序创建一个框架。我正在使用 Arduino IDE 来编译和部署程序。
由于微处理器的堆内存通常较低,因此我想尽可能只使用堆栈内存。
最小示例:
完整示例代码可见here.
我会描述我认为最有趣的部分。
iMinExApplication(接口):
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];
};
tMinExCoordinator(master,调用添加的应用)
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 草图)
#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
('HERE!'
在 tMinExCoordinator
class 定义中,第 57 行在 tMinExClasses.hpp).
没有它我似乎无法让它工作。 除了在堆栈内存中分配内存外,我还可以通过其他什么方式实现它?
要求:
- 堆栈内存分配
- 要使用的接口
我知道智能指针,但不确定它们是否使用堆内存。另外,我希望最小示例尽可能简洁。
I cannot seem to get it to work without it. In what other way could I implement this, but only allocating memory in stack memory?*
您可以预先分配一个足够大小的字节数组,然后使用 placement-new
to construct objects inside of that array (see std::aligned_storage 来帮助您。)多态性只需要 pointers/references 在运行时工作,不需要动态分配。
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
class 使用固定的内存缓冲区,如果在堆栈上构建向量,它将在堆栈上:
#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();
}
}
};
您可以在协调器中使用 class,并对其进行一些小的添加,以便它可以与循环一起使用,例如:
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;
};
I have though of smart pointers, but am unsure if they use heap memory or not.
默认情况下,它们依赖于 new
和 delete
,因此是动态内存。但是,您 可以 为它们提供指向堆栈内存的指针,如果您还为它们提供不会释放该内存的自定义删除器。