【问题标题】:C++ composition without using the heap in embedded systems在嵌入式系统中不使用堆的 C++ 组合
【发布时间】:2021-12-04 09:38:39
【问题描述】:

我对 C++ 还很陌生,这也是我在这里的第一篇文章。我正在尝试在嵌入式系统项目中使用 C++,这样我就可以采用 OOP 方法。我正在使用 AVR 交叉包工具链(AVR G++ 编译器)

我的问题是这样的:

根据我的阅读,堆不应该用于嵌入式系统中的动态内存分配。无论如何,无论如何,AVR G++ 中都没有“新”的实现。我正在使用组合,从一个 USART 驱动程序(我们称之为服务)和一个记录器(单例模式,也是一个服务)开始。

据我了解,服务应该在实例化时使用构造函数参数传递它们的依赖关系,但是当我尝试以这种方式组合所需的对象时,出现以下错误:

Main/main.cpp: In function 'int main()':
Main/main.cpp:21:13: error: request for member 'log' in 'logSystem', which is of non-class type 'LogSystem(Usart)'
   21 |   logSystem.log("Hello");
      |             ^~~
make: *** [Main/main.o] Error 1

我的感觉是我将对象作为构造函数参数传递的语法是错误的,但我不确定它应该是什么,因为我能找到的所有示例都使用构造函数定义中的“new”关键字来创建免费商店中的对象。有人可以帮忙吗?

代码:

在“usart.h”中:

#include <avr/io.h>
#include <util/setbaud.h>

class Usart
{
public:
  // Constructor and destructor
  Usart();
  ~Usart();

  // Initialisation routine
  static void const init(void);

  // Utility function to transmit a string
  static void const print(const char myString[]);
};

在“logger.h”中:

#include "usart.h"

class LogSystem
{
public:

  LogSystem(Usart usart);
  ~LogSystem();

  Usart usart;

  static void const log(char *msg);

};

在“logger.cpp”中

#include "logger.h"

LogSystem::LogSystem(Usart usart)
{
  Usart usart;
  usart.init();
}

LogSystem::~LogSystem()
{
}

LogSystem::log(char *msg)
{
  usart.print(msg);
}

在“main.cpp”中:

#include "logger.h"


int main()
{
    LogSystem logSystem(Usart usart);

    while(1)
    {
        logSystem.log("Hello");
    }

    return 0;
}

【问题讨论】:

  • 你有一堆额外的使用类名Usart 散落在代码周围。 LogSystem logSystem(Usart usart); 不会创建名为 logSystemLogSystem 对象的实例,它声明了一个名为 logSystem函数,该函数将单个 Usart 实例作为其参数并返回一个 @ 987654333@。在您的LogSystem 构造函数中,Usart usart; 行声明了构造函数的局部变量,同时隐藏了usart 参数 LogSystem::usart 成员变量。
  • 感谢您的评论@NathanPierson - 我明白您在说什么,我觉得这就是问题所在,但是我仍然不清楚应该如何正确执行这些实例化,可以请为我详细说明一下?我不明白的部分是我应该在构造函数中而不是做什么:new Usart = usart;
  • 您可能想查看initializer lists 以了解如何初始化值。您还将一个特定的 Usart 实例传递给构造函数。但是按照目前的设计,我不确定它到底应该做什么,因为Usart 无论如何只有静态方法,所以我不确定它应该如何组合成LogSystem
  • 您的代码中有一些基本错误。回顾一些 C++ 书籍的早期章节,了解如何定义类和成员函数,会很棒。
  • 感谢@NathanPierson - 你说得对,我一开始就对静态声明有错误的想法。

标签: c++ embedded avr composition


【解决方案1】:

[...] 堆不应用于嵌入式系统中的动态内存分配。

这取决于。我目前在一个具有最高安全相关要求的嵌入式项目中,我们使用new,但不是delete。所以我们有一个堆,但不要“动态”分配,因为所有分配的对象都在运行时保留。

无论如何,无论如何,AVR G++ 中都没有“新”的实现。

这是真的吗?我从来没有检查过...可能需要提供一个堆才能使用new

据我了解,服务应该在实例化时使用构造函数参数传递它们的依赖关系,[...]

这是个好主意。 ;-) 它有助于单元测试。

对于您的句法和设计问题:这就是我将如何编写您的源代码的方式。

“usart.h”:

所有方法都是非静态的,可以访问成员变量。

返回类型上的const 属性什么都不做。您的意思是声明方法常量吗?那么const属于参数列表之后。但是,如果这样的方法改变了任何成员变量,这个属性可能是错误的。

#include <avr/io.h>
#include <util/setbaud.h>

class Usart
{
public:
  Usart();
  ~Usart();

  void init(void);

  void print(const char myString[]);
};

“logger.h”:

只需提供并存储对 USART 的引用即可避免复制。

#include "usart.h"

class LogSystem
{
public:
  LogSystem(Usart& usart);
  ~LogSystem();

  void log(const char *msg);

private:
  Usart& _usart;
};

“logger.cpp”

成员变量_usart在构造函数中直接初始化,在执行任何语句之前。

#include "logger.h"

LogSystem::LogSystem(Usart& usart) : _usart(usart)
{
  _usart.init();
}

LogSystem::~LogSystem()
{
}

void LogSystem::log(const char *msg)
{
  _usart.print(msg);
}

“main.cpp”:

在堆栈上提供 USART 对象,作为记录器。

#include "logger.h"

int main()
{
    Usart usart;
    LogSystem logSystem(usart);

    while(1)
    {
        logSystem.log("Hello");
    }

    return 0;
}

单例设计模式自发明以来就被弃用了,因为它很难测试。只需使用一个对象或一个限制对象工厂。

【讨论】:

  • 太棒了,我只是根据您的建议重新编写了源代码,效果很好,非常感谢!您为持续程序长度的对象分配堆空间的建议很有趣,我会看一下。我指的是我在这里读到的内容 [avrfreaks.net/forum/c-new-delete-operator-confusion] 这似乎你必须为 new 和 delete 编写自己的实现。显然,我需要返回并重新阅读有关通过引用等传递的章节!您对弃用单例模式的评论也会被记录下来。干杯!
猜你喜欢
  • 2012-07-26
  • 2010-09-12
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 2010-11-14
  • 2021-07-21
  • 2014-04-14
  • 1970-01-01
相关资源
最近更新 更多