std::stack、pop() returns 相同值的奇怪行为
Strange behaviour with std::stack, pop() returns same value
我有 class 使用 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 通知回调):
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
块结束)。但是堆栈中的指针仍然存在。那时,取消引用此指针会调用 undefined behavior,因此当您在将指针从堆栈中弹出后执行此操作时,您得到的结果是未定义的行为。
在您的特定情况下,编译器似乎已为所有 messageId
实例重新使用相同的内存位置,这意味着在推送所有项目后,该内存位置仍保留最后推送的值物品。但是要重申:这是未定义的行为,你不应该依赖它。
相反,将 值 的副本推送到堆栈上,或者将指针推送到堆栈上,指向将在指针(堆栈)的生命周期内保持分配的内存.
我有 class 使用 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 通知回调):
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
块结束)。但是堆栈中的指针仍然存在。那时,取消引用此指针会调用 undefined behavior,因此当您在将指针从堆栈中弹出后执行此操作时,您得到的结果是未定义的行为。
在您的特定情况下,编译器似乎已为所有 messageId
实例重新使用相同的内存位置,这意味着在推送所有项目后,该内存位置仍保留最后推送的值物品。但是要重申:这是未定义的行为,你不应该依赖它。
相反,将 值 的副本推送到堆栈上,或者将指针推送到堆栈上,指向将在指针(堆栈)的生命周期内保持分配的内存.