You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

关键说明

  1. Placement New:用于在已分配的内存上构造对象,确保vector的构造函数执行,初始化内部成员(如元素指针、大小、容量)。
  2. 元素访问:由于eventStack是指针,需先解引用(*eventStack)再使用[],或直接调用eventStack->at(index)(带越界检查),也可通过迭代器遍历。
  3. 析构与释放:必须先调用vector的析构函数,释放它管理的元素内存,再调用heap_caps_free释放PSRAM的内存,避免内存泄漏。

内容的提问来源于stack exchange,提问作者ADL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:24:57