Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 观察者模式的实现使用了大量的RAM——我怎样才能知道在哪里以及为什么?_C++_Microcontroller_Observer Pattern - Fatal编程技术网

C++ 观察者模式的实现使用了大量的RAM——我怎样才能知道在哪里以及为什么?

C++ 观察者模式的实现使用了大量的RAM——我怎样才能知道在哪里以及为什么?,c++,microcontroller,observer-pattern,C++,Microcontroller,Observer Pattern,我正在创建observer模式的简单实现,发现它使用了大量RAM。我想知道为什么以及如何解决这个问题——事实上,我的微控制器的RAM已经满了。以下是我使用的类(和一个函数): 因此,我的问题是: 我如何追踪RAM的使用情况,找出是什么占用了我这么多宝贵的内存 什么是好的选择?如果涉及到不使用std::function和std::bind,有没有更省力的方法?如果解决方案将通知参数的数量限制为一个较小的值(零或一个是好的),那么就可以了 我不能使用boost.signals 为什么我需要一些

我正在创建observer模式的简单实现,发现它使用了大量RAM。我想知道为什么以及如何解决这个问题——事实上,我的微控制器的RAM已经满了。以下是我使用的类(和一个函数):

因此,我的问题是:

  • 我如何追踪RAM的使用情况,找出是什么占用了我这么多宝贵的内存
  • 什么是好的选择?如果涉及到不使用
    std::function
    std::bind
    ,有没有更省力的方法?如果解决方案将通知参数的数量限制为一个较小的值(零或一个是好的),那么就可以了
我不能使用
boost.signals


为什么我需要一些灵活性


我的设备包含一个显示器,我正在为此编写简单的小部件。我想使用观察者模式的一个例子是按钮和硬件按钮事件:当按钮被“点击”(按下“进入”硬件按钮)时,其他一些小部件应该改变状态。随着时间的推移,小部件的列表不断增加,自定义“操作类”的数量也不断增加,它们的
operator()
被小部件调用,但当我需要在一个事件发生时发生多个事件,或者当一个事件与一个值(一个索引、某个已更改的数字,…)紧密耦合时,这还不够
std::function
对于这样一个平台来说是太过了

我强烈怀疑,在这个平台上,您不需要多个活动信号。因此,创建一个模板类
SignalParam
,该类保留当前参数。这意味着所有观察者都可以拥有签名
void()
,并且您可以只存储一个普通函数指针

类似地,
bind
参数最好存储在另一个单例中

虽然为了类型安全,您应该保持
连接
信号
模板化,但将所有工作卸载到公共基类。这意味着您将没有相同函数的那么多副本


顺便说一句,在列表的前面添加一个新连接更容易:
conn->next=connections;连接=连接。保存列表遍历。

双向进行核心转储,对字符串运行
并区分结果。跟踪堆栈/全局分配的数据节的方法是查看链接器映射输出或nm的结果。对于分析运行时内存使用情况(从堆中分配),像valgrind这样的工具可能很有用。比较映射输出听起来是可行和有用的。虽然我还没有找到罪犯@n、 m.“很多”是16KB可用内存中的2KB。如果当我添加更多信号和连接时,这一点不会增加,我可能会使用更大的mcu。好吧,几乎所有的动态数组(即
std::vector
)都比链表表现得更好:它们只使用
sizeof(t)
来存储每个元素(而不是
sizeof(t)+sizeof(Node*)+堆元数据
),与链表相比,它的缓存使用速度快得多。我建议您使用
std::vector
回调,而不是这种链表。谢谢您的回答。给所有观察者一个
void(void)
签名听起来不错,我可以把复杂性转移到观察者身上。我不太熟悉
bind
并将这些参数存储在单例中,我该怎么做?如果您觉得合适的话,我们可以谈谈您的建议?关于
SignalParam
:我花了一段时间才明白这个想法
SignalParam
专门用于每个参数列表,并包含一组与参数匹配的静态参数。这意味着我可以在调用所有观察者之前设置适当的信号参数,然后他们反过来检查信号参数,而不是将其作为“真实”参数传递。这就是你的建议吗?一旦我理解了它,这似乎是个好主意,但是:如果我决定“链接”信号(一个信号触发另一个信号,参数相同,但值不同),模板方法就会中断。@Christoph:是的。为小型系统开发完全是为了权衡。例如,我知道牺牲
std::function
会失去灵活性,但会节省空间。原因很简单:类型擦除需要一些空间。我创建了一个简单的委托类模板,似乎可以工作。我只在我的PC上测试了它,而不是在目标系统上,但它似乎按预期工作:据我所知,它将允许更多的链接信号和信号参数,而不是我所需要的。
#include <functional>

template<typename... args>
class Connection
{
  public:
    Connection(std::function<void(args...)> func)
      : f(func),
      next(NULL)
    {
    }
    std::function<void(args...)> f; // the function object to execute
    Connection* next; // pointer to next connection in linked list
  private:
    Connection(const Connection&); // no copy construction
    Connection& operator=(const Connection&); // no assignment
};

template<typename... args >
class Signal
{
  public:
    typedef Connection<args...> ConnectionType;
    Signal()
      : connections(NULL)
    {

    }
    void operator()(args... arg) const
    {
      // call all observers
      const ConnectionType* c = connections;
      while(c != NULL)
      {
        c->f(arg...);
        c = c->next;
      }
    }
    void add(ConnectionType* conn) // add an observer
    {
      if (connections == NULL)
      {
        connections = conn;
      }
      else
      {
        lastConnection()->next = conn;
      }
    }
  private:
    Signal(const Signal&); // no copy construction
    Signal& operator=(const Signal&); // no assignment
    ConnectionType* lastConnection() const
    {
      ConnectionType* c = connections;
      if (c == NULL)
      {
        return c;
      }
      while(c->next != NULL)
      {
        c = c->next;
      }
      return c;
    }
    ConnectionType* connections;
};

template<typename Sig, typename Func >
typename Sig::ConnectionType* connect(Sig& sig, Func func)
{
  typedef typename Sig::ConnectionType connection_type;
  connection_type* pConn = new connection_type(func);
  sig.add(pConn);
  return pConn;
}

class Something
{
  public:
  void doSomething(const int& i, const int& offset) const
  {
    // Serial is a USB Virtual Serial device interface
    Serial.print("something ");Serial.println(i + offset);
  }
};
Signal<const int&> intSig;
Something some;
connect(intSig, std::bind(&Something::doSomething, &some, std::placeholders::_1, 2));
intSig(121); // should print "something 123"
-Wall
-mthumb
-s
-Os
-mcpu=cortex-m4
-MMD
-std=gnu++0x
-felide-constructors
-fno-exceptions
-fno-rtti
-ffunction-sections
-fdata-sections
-nostdlib
-fpermissive