У меня есть класс, который использует 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
Поэтому я пытаюсь написать подобный код в онлайн-компиляторе:
И это прекрасно работает.
Что я делаю неправильно?
std::stack<uint8_t*> pendingNotification;
У вас есть стопка указателей. Чтобы это имело смысл, вам нужно иметь кучу различных объектов для стека, на которые будут помещаться указатели, и эти объекты должны оставаться действительными до тех пор, пока вы намереваетесь использовать стек указателей. Ваш код этого не делает.
Не создавайте стопки указателей, если у вас нет для этого веских причин. Вместо этого создайте стеки значений данных.
notificationService->addPendingNotification(messageId);
толкает указатель на локальную переменную ( messageId
массив) на стек.
Область действия этой локальной переменной заканчивается в некоторый момент позже (как только включается if
блок заканчивается). Но указатель в стеке все еще остается. На этом этапе разыменование этого указателя вызывает неопределенное поведение, поэтому, когда вы делаете после удаления указателя из стека, вы получите неопределенное поведение.
В вашем конкретном случае кажется, что компилятор повторно использовал одну и ту же область памяти для всех messageId
экземпляры, что означает, что после нажатия всех элементов это место в памяти по-прежнему содержит значение последнего нажатого элемента. Но повторим: это неопределенное поведение, и вы не должны на это полагаться.
Вместо этого, либо нажмите копию значение на стек, или поместите указатель на стек в память, которая останется выделенной на время жизни указателя (стека).