将指向对象的指针数组作为构造函数参数传递

Pass array of pointers to objects as constructor parameter

提问人:Viermusketiere 提问时间:3/9/2023 最后编辑:DharmanViermusketiere 更新时间:3/9/2023 访问量:119

问:

我需要传递一个指向数组的指针,其中包含指向对象列表的指针作为新生成对象的构造函数参数。如果我设法让它在 ESP32 上编译和运行,似乎存在越界内存访问。

不要担心中断的措辞;系统正在读取外部MCP23017 GPIO扩展器的寄存器,该扩展器仅在内部处理中断。该例程旨在定期检查MCP23017s引脚之一是否发生中断,以及中断发生在哪个引脚上。然后,应选择与引脚对应的对象,并调用该对象的函数。action()

下面是编译的代码:

class StateManager {
    private:
        MCP *mcp1;
        StateSensor * arrSensor;
    public:
        StateManager(MCP * pMcp1, StateSensor * pArrSensor);
        void checkInterrupt();
};

//Constructor
StateManager::StateManager(MCP * pMcp1, MCP * pMcp2, StateSensor * pArrSensor) {
    mcp1 = pMcp1;
    mcp2 = pMcp2;
    arrSensor = pArrSensor;
}

//Function in which the faulty access happens
void StateManager::checkInterrupt() {
    uint8_t pinLI1 = mcp1->getLastInterruptPin();
    ESP_LOGI(TAG, "pinLI1: %d", pinLI1);
    if ( pinLI1 != 255 ) {
        ESP_LOGI(TAG, "If clause reached");
        for( uint8_t i = 0; i < 16; i++ ) {
            ESP_LOGI(TAG, "for: %d, getPin(): %d", i, arrSensor[i].getPin());
            if( arrSensor[i].getPin() == pinLI1 ) {
                ESP_LOGI(TAG, "Hit: %d", i);
                arrSensor[i].action();
                break;
            }
        }
    }
}

StateSensor sens01(1,  &mcp02, 7);
StateSensor sens02(2,  &mcp02, 6);
StateSensor sens03(3,  &mcp02, 5);
StateSensor sens04(4,  &mcp02, 4);
StateSensor * arrSens[32] = { &sens01, &sens02, &sens03, &sens04 }

StateManager sm1(&mcp02, &mcp03, *arrSens);

void setup() {
    //...
}

void loop() {
    sm1.checkInterrupt();
}

以下是 (1) 触发数组的第一个元素和 (2) 触发数组的第二个元素的日志输出,这会导致随机返回值。的预期值为 0 到 15。255 在未发生中断时返回。getPin()mcp1->getLastInterruptPin()

[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
(1)
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 7
[stateSensor.cpp:57] checkInterrupt(): [StateSensor] If clause reached
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 0, getPin(): 7
[stateSensor.cpp:61] checkInterrupt(): [StateSensor] Hit: 0
[stateSensor.cpp:35] action(): [StateSensor] 1 action!
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
(2)
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 6
[stateSensor.cpp:57] checkInterrupt(): [StateSensor] If clause reached
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 0, getPin(): 7
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 1, getPin(): 0
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 2, getPin(): 4
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 3, getPin(): 0
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 4, getPin(): 10
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 5, getPin(): 0
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 6, getPin(): 8
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 7, getPin(): 28
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 8, getPin(): 223
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 9, getPin(): 211
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 10, getPin(): 1
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 11, getPin(): 131
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 12, getPin(): 251
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 13, getPin(): 122
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 14, getPin(): 32
[stateSensor.cpp:59] checkInterrupt(): [StateSensor] for: 15, getPin(): 112
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255
[stateSensor.cpp:55] checkInterrupt(): [StateSensor] pinLI1: 255

当触发数组的第一个或最后一个元素时,将从数组中读取指向对象的右指针。对于介于两者之间的所有元素,该操作将返回一个介于 0 和 255 之间的随机数。arrSensor[i].getPin()

如何有效地处理包含元素的数组的切换,同时解决越界内存访问的问题?还是我忽略了我方法中的一个根本错误?

指针 esp32 arduino-c++ arduino-esp32

评论


答:

2赞 2 revs001 #1

StateSensor * arrSensor;是指向单个对象的指针,或者它是对象数组(不是指针 - 如 )。StateSensorStateSensorStateSensor * my_array = new StateSensor[10]

但是,看起来您想要一个指针数组,您可以将其声明为 并将构造函数的签名更改为 .(我猜你没有使用,因为这是一个微处理器)。StateSensorStateSensor **StateManager(MCP * pMcp1, StateSensor ** pArrSensor);std::vector

此外,传递给构造函数,而不是整个数组。要传递数组,请使用 .StateManager sm1(&mcp02, &mcp03, *arrSens);arrSens[0]StateManager sm1(&mcp02, &mcp03, arrSens);

然后,您需要更改函数以处理指针数组,用于取消引用它们。checkInterrupt->

for (uint8_t i = 0; i < 16; i++) {
    ESP_LOGI(TAG, "for: %d, getPin(): %d", i, arrSensor[i]->getPin());
    if (arrSensor[i]->getPin() == pinLI1) {
        ESP_LOGI(TAG, "Hit: %d", i);
        arrSensor[i]->action();
        break;
    }
}

这就引出了最后一点:循环最多可以迭代 16 次,但数组中只有 4 个指针。如果保证及时命中,则不是问题,但如果没有,则需要一种方法来确保不会读取数组的末尾或取消引用 .breaknullptr

评论

0赞 Viermusketiere 3/9/2023
谢谢你,解决了我的问题,并向我解释了我的错误。你对 std::vector 的看法是正确的,循环迭代是安全的,我简化并缩短了这篇文章的对象列表,迭代次数与实际数组的大小相匹配。