Странное поведение с std::stack, pop() возвращает то же значение

У меня есть класс, который использует std::stack:

class NotificationService{
    public:
        void addPendingNotification(uint8_t *uuid);
        uint8_t* getNextPendingNotification();
        void popPending();
    private:
        std::stack<uint8_t*> pendingNotification;
};

void NotificationService::addPendingNotification(uint8_t *uuid) {
    pendingNotification.push(uuid);
    Serial.print("Insert to stack: ");
    Serial.print(uuid[0]);
    Serial.print(uuid[1]);
    Serial.print(uuid[2]);
    Serial.println(uuid[3]);
}

uint8_t *NotificationService::getNextPendingNotification() {
    if (pendingNotification.size() > 0) {
        uint8_t *uuid = pendingNotification.top();
        Serial.println(*uuid);
        pendingNotification.pop();
        return uuid;
    } else {
        return NULL;
    }
};

void NotificationService::popPending(){
    while (!pendingNotification.empty())
    {
        uint8_t *uuid = pendingNotification.top();
        Serial.print(uuid[0]);
        Serial.print(uuid[1]);
        Serial.print(uuid[2]);
        Serial.println(uuid[3]);
        pendingNotification.pop();
    }
}

Я добавляю в мой основной код (BLE Notification Callback):

static void NotificationSourceNotifyCallback(
    BLERemoteCharacteristic *pNotificationSourceCharacteristic,
    uint8_t *pData,
    size_t length,
    bool isNotify)
{
    if (pData[0] == 0)
    {
        uint8_t messageId[4] = {pData[4], pData[5], pData[6], pData[7]};
        switch (pData[2])
        {
            //Incoming Call
        case 1:
        {
            notificationService->addPendingNotification(messageId);
        }
/** code **/
}

Все работает нормально, пока я не хочу вытолкнуть элементы из стека, тогда каждый элемент имеет одинаковое значение (последний вставленный элемент).

Серийный журнал печати:

Insert to stack: 8000
Insert to stack: 32000
Insert to stack: 19000
Insert to stack: 44000
Insert to stack: 4000
Pop whole stack:
4000
4000
4000
4000
4000

Поэтому я пытаюсь написать подобный код в онлайн-компиляторе:

http://cpp.sh/7hv4

И это прекрасно работает.

Что я делаю неправильно?

2 ответа

Решение
std::stack<uint8_t*> pendingNotification;

У вас есть стопка указателей. Чтобы это имело смысл, вам нужно иметь кучу различных объектов для стека, на которые будут помещаться указатели, и эти объекты должны оставаться действительными до тех пор, пока вы намереваетесь использовать стек указателей. Ваш код этого не делает.

Не создавайте стопки указателей, если у вас нет для этого веских причин. Вместо этого создайте стеки значений данных.

notificationService->addPendingNotification(messageId);

толкает указатель на локальную переменную (messageId массив) на стек.

Область действия этой локальной переменной заканчивается в некоторый момент позже (как только включается if блок заканчивается). Но указатель в стеке все еще остается. В этот момент разыменование этого указателя вызывает неопределенное поведение, поэтому, когда вы делаете это после удаления указателя из стека, вы получите неопределенное поведение.

В вашем конкретном случае кажется, что компилятор повторно использовал одну и ту же область памяти для всех messageId экземпляры, что означает, что после нажатия всех элементов это место в памяти по-прежнему содержит значение последнего нажатого элемента. Но повторим: это неопределенное поведение, и вы не должны на это полагаться.

Вместо этого либо поместите копию значения в стек, либо поместите указатель на стек в память, которая останется выделенной на время существования указателя (стека).

Другие вопросы по тегам