ESP32-S3 PSRAM中vector结构体指针的数据访问方法咨询
ESP32-S3 PSRAM中std::vector数据访问问题
在启用PSRAM的ESP32-S3上,使用std=gnu++14标准尝试在PSRAM中创建std::vector,已完成PSRAM内存分配、vector创建、添加测试记录(确认容量增长)、删除起始记录(确认容量减少)等操作,但无法通过指针读取vector内的结构体数据,相关尝试代码已注释。
测试代码
struct EventRecord_t { // owned by MESH_ROOT uint8_t node = 0; uint8_t errorCount; }; void eventsStart(){ void* eventsRam; eventsRam = heap_caps_malloc(1000000, MALLOC_CAP_SPIRAM); // 从PSRAM分配内存 std::vector<EventRecord_t>* eventStack; // 声明指向结构体vector的指针 eventStack = (std::vector<EventRecord_t>*) eventsRam; // 在PSRAM中"创建"vector EventRecord_t eventRecord; // 创建并填充记录 eventRecord.node = 1; eventRecord.errorCount = 34; eventStack->push_back(eventRecord); // 添加记录到eventStack std::cout << "Size: " << eventStack->size() << std::endl; // 确认大小增长 eventRecord.node = 2; eventStack->push_back(eventRecord); std::cout << "Size: " << eventStack->size() << std::endl; eventRecord.node = 3; eventStack->push_back(eventRecord); std::cout << "Size: " << eventStack->size() << std::endl; // 尝试访问eventStack数据的失败代码 // eventRecord = eventStack[0]; // uint8_t inode = eventStack[0]->node; eventStack->erase(eventStack->begin()); // 删除第一条记录 std::cout << "Size: " << eventStack->size() << std::endl; // 确认大小减少 eventStack->erase(eventStack->begin()); std::cout << "Size: " << eventStack->size() << std::endl; eventStack->erase(eventStack->begin()); std::cout << "Size: " << eventStack->size() << std::endl; free(eventsRam); }
输出结果
Size: 1 Size: 2 Size: 3 Size: 2 Size: 1 Size: 0
问题原因与修正方案
核心问题
直接将heap_caps_malloc分配的内存强制转换为std::vector指针是错误的——vector的构造函数未被调用,内存中的vector对象处于未初始化状态,内部的指针、大小、容量等成员都是随机值。虽然push_back和size()看似正常输出,但整个操作属于未定义行为,后续的元素访问自然会失败。
修正后的代码
struct EventRecord_t { // owned by MESH_ROOT uint8_t node = 0; uint8_t errorCount; }; void eventsStart(){ // 分配足够容纳vector对象+元素的PSRAM内存 size_t vectorObjSize = sizeof(std::vector<EventRecord_t>); void* eventsRam = heap_caps_malloc(vectorObjSize + 1000000, MALLOC_CAP_SPIRAM); // 使用placement new在已分配的PSRAM内存上构造vector std::vector<EventRecord_t>* eventStack = new(eventsRam) std::vector<EventRecord_t>(); EventRecord_t eventRecord; eventRecord.node = 1; eventRecord.errorCount = 34; eventStack->push_back(eventRecord); std::cout << "Size: " << eventStack->size() << std::endl; eventRecord.node = 2; eventStack->push_back(eventRecord); std::cout << "Size: " << eventStack->size() << std::endl; eventRecord.node = 3; eventStack->push_back(eventRecord); std::cout << "Size: " << eventStack->size() << std::endl; // 正确访问vector元素的三种方式 // 方式1:解引用指针后使用operator[] EventRecord_t firstRecord = (*eventStack)[0]; std::cout << "First node: " << (int)firstRecord.node << ", errorCount: " << (int)firstRecord.errorCount << std::endl; // 方式2:使用at()方法(带越界检查) EventRecord_t secondRecord = eventStack->at(1); std::cout << "Second node: " << (int)secondRecord.node << ", errorCount: " << (int)secondRecord.errorCount << std::endl; // 方式3:迭代器遍历 for (const auto& record : *eventStack) { std::cout << "Node: " << (int)record.node << ", errorCount: " << (int)record.errorCount << std::endl; } eventStack->erase(eventStack->begin()); std::cout << "Size: " << eventStack->size() << std::endl; eventStack->erase(eventStack->begin()); std::cout << "Size: " << eventStack->size() << std::endl; eventStack->erase(eventStack->begin()); std::cout << "Size: " << eventStack->size() << std::endl; // 必须手动调用vector析构函数,释放其管理的元素内存 eventStack->~vector(); // 释放PSRAM内存 heap_caps_free(eventsRam); }
关键说明
- Placement New:用于在已分配的内存上构造对象,确保vector的构造函数执行,初始化内部成员(如元素指针、大小、容量)。
- 元素访问:由于
eventStack是指针,需先解引用(*eventStack)再使用[],或直接调用eventStack->at(index)(带越界检查),也可通过迭代器遍历。 - 析构与释放:必须先调用vector的析构函数,释放它管理的元素内存,再调用
heap_caps_free释放PSRAM的内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者ADL
相关产品推荐
相关产品推荐

