【问题标题】:Changing one object's member in a LinkedList changes all objects更改 LinkedList 中一个对象的成员会更改所有对象
【发布时间】:2020-11-13 07:55:02
【问题描述】:

对不起,我对 C++ 很陌生,我正在编写一个 Arduino 草图。

我想实现一种面向命令的方法,其中我有一个命令队列、一个父虚拟/抽象类 Command,并且每个实际命令都继承自该类。

为了实现这个队列,我使用了我从 Arduino 的库管理器(某种“图书馆商店”)获得的 LinkedList 库。所以我有:

LinkedList<Command*> queue = new LinkedList<Command*>();

我添加了 * 因为否则它不会编译。

问题是我正在使用“new”运算符将命令推送到队列。如果我只使用列表中的一个对象,它可以正常工作,但目的是在队列中有多个命令,问题是如果我更改实例的成员,它将更改所有其他实例也在队列中,就好像它们都指向同一个实例一样。当然,变量没有声明为静态的。

我怀疑是因为列表初始化中的*,但说实话,我还没有完全理解C++指针,这只是一个疯狂的猜测。

更新 #1:回答 molbdnilo 请求。这是最小的可重现示例(您需要 Luis Llamas 创建的 LinkedListLib 库,可以从 Arduino Library Manager 获得):

#include <LinkedListLib.h>

// Definiciones
class Command {

  private:
  String state = "NOT_EXEC"; // Estados: NOT_EXEC, NOT_FINISHED, FINISHED
  
  public: 
  virtual void init() = 0; // Función de inicialización de comando
  virtual void exec() = 0; // Función de ejecución del comando
  virtual void finish() = 0; // Función de finalizado del comando
  void setStatus(String s){ state = s;};
  virtual ~Command(){};
  String getStatus(){
    return state;
  } // Entrega el estado del comando
  
  
};

class Parpadear : public Command{
  private: 
  long t;
  int c = 0;
  int stat;
  int mil;
  int rep;
  
  public:
  Parpadear(int x, int y){
  mil = x;
  rep = y;
  }
  void init() override{
    t = millis();
    stat = HIGH;
    digitalWrite(LED_BUILTIN, stat);
  }

  void exec() override{
   if (millis() - t > mil){
    stat = stat == HIGH ? LOW : HIGH; 
    digitalWrite(LED_BUILTIN, stat);
    t = millis();
    c++;
    }

    if(c == rep){
      setStatus("FINISHED");
    }
  }

  void finish() override{

  }

  Parpadear::~Parpadear(){
    
  }
};

// Estados: 1 = init, 2 = exec, 3 = main
const int INIT = 1; // Initialization state
const int EXEC = 2; // Command execution state
const int MAIN = 3; // Main loop code state
int state = INIT;
long init_time;
LinkedList<Command*> queue = LinkedList<Command*>();
String commandResult;


void setup() {
  // Inicialización de Arduino
  pinMode(LED_BUILTIN, OUTPUT); // Configura LED en tabla  
  Serial.begin(9600);

}

void loop() {
  // Máquina de estados para control global de la estructura orientada a comandos
  switch(state){
    case INIT:
      // Inicialización de la máquina de estados
      init_time = millis(); // Obtener el tiempo en el que la máquina de estados se empezó a ejecutar por primera vez.
      state = EXEC; // Realizar transición a ejecución de comandos.
      queue.InsertHead(new Parpadear(2000, 4));
      queue.InsertTail(new Parpadear(300, 50));
      break;
    case EXEC:
      // Ejecución de comandos en cola
      if(queue.GetSize() > 0){
        if(queue.GetHead()->getStatus() == "NOT_EXEC"){
          queue.GetHead()->init();
          queue.GetHead()->setStatus("NOT_FINISHED");
        }
        queue.GetHead()->exec(); // Ejecuta primer comando en la cola
        if(queue.GetHead()->getStatus() == "FINISHED"){
          //Serial.println(queue.GetHead()->getStatus());
          queue.GetHead()->finish();
          queue.RemoveAt(0); // Quitar el primer comando de la lista
        }
      }
      break;
    case MAIN:
      break;
  }

}

更新 #2:关于 Botje 的问题:

我如何确定这会改变两个实例?

(请参考switch case EXEC,代码参考)

从父Command类继承的所有Commands(在这种情况下,只实现了Parpadear类),都有一个名为“state”的String变量存储命令的状态,所以每次一个命令排队时,它只有当它完成执行时,这个“状态”变量才会将其值更改为“FINISHED”(否则它将是“NOT_FINISHED”),这会触发队列从列表中删除命令。

使用 Arduino 的串行监视器工具,我可以看到在排队 2 个命令后,第一个命令将相应地执行,但是一旦第一个被删除,第二个也被立即删除。我使用 Serial.println 为每个命令打印“状态”变量,当另一个不应该时,所有这些都导致“完成”。

还打印了变量“c”,它只是一个计数器,在这两种情况下,它都等于相同的值 (4),因为在第二种情况下,“c”甚至还没有被操纵。

【问题讨论】:

  • 请阅读minimal reproducible example,然后创建一个。
  • 您如何确定队列中的所有其他实例也发生了变化?受此影响的代码在哪里?
  • 感谢大家的回答,我更新了问题以解决您的问题。再次感谢大家!

标签: c++ oop c++11 arduino linked-list


【解决方案1】:

改用另一个库解决了这个问题。具有讽刺意味的是,由同一作者开发。

在这种情况下,我使用的是 List 而不是 LinkedList,有什么区别吗?

可能其他库已经过时,或者处理指针的方式晦涩难懂,但为了记录,我现在使用的库是“ListLib”,也可以从Arduino库管理器获得

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    • 1970-01-01
    相关资源
    最近更新 更多