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

树莓派4B上libcamera应用多帧内存存储崩溃问题求助

问题根源:默认拷贝构造/赋值的浅拷贝导致重复释放内存

你的代码崩溃的核心原因是ImageData类没有正确处理拷贝语义:

  • C++编译器会自动生成默认的拷贝构造函数和赋值运算符,这些默认实现会浅拷贝所有成员变量,包括buffer指针。
  • 当imageBuffer存储多帧时,vector可能因容量不足触发扩容,此时会对现有ImageData对象进行拷贝。多个对象会共享同一个buffer指针,当这些对象被析构(比如扩容时旧内存被释放),会多次调用delete[] buffer,触发double free错误,导致程序崩溃。
  • 单帧存储时vector无需扩容,仅存在一个ImageData对象,析构时仅释放一次内存,因此不会出现问题。

修复方案

方案1:禁用拷贝,显式实现移动语义(推荐,适配你的现有代码)

通过禁用拷贝构造和赋值运算符,强制使用移动语义,确保每个内存块仅被一个ImageData对象拥有:

class ImageData 
{
public:
    ImageData(std::vector<libcamera::Span<uint8_t>> m, StreamInfo i, libcamera::ControlList met, std::string fil, std::string cam) :
        mem(m),
        info(i),
        metadata(met),
        filename(fil),
        cam_name(cam),
        buffer(new uint8_t[mem[0].size_bytes()]) {}
        
    ~ImageData() { delete[] buffer; }

    // 禁用拷贝构造和赋值,避免浅拷贝
    ImageData(const ImageData&) = delete;
    ImageData& operator=(const ImageData&) = delete;

    // 显式实现移动构造,转移内存所有权
    ImageData(ImageData&& other) noexcept :
        mem(std::move(other.mem)),
        info(std::move(other.info)),
        metadata(std::move(other.metadata)),
        filename(std::move(other.filename)),
        cam_name(std::move(other.cam_name)),
        buffer(other.buffer)
    {
        other.buffer = nullptr; // 清空原对象指针,避免析构时重复释放
    }

    // 显式实现移动赋值
    ImageData& operator=(ImageData&& other) noexcept
    {
        if (this != &other)
        {
            delete[] buffer; // 释放当前对象的旧内存
            // 转移所有成员的所有权
            mem = std::move(other.mem);
            info = std::move(other.info);
            metadata = std::move(other.metadata);
            filename = std::move(other.filename);
            cam_name = std::move(other.cam_name);
            buffer = other.buffer;
            other.buffer = nullptr;
        }
        return *this;
    }
    
    std::vector<libcamera::Span<uint8_t>> mem;
    StreamInfo info;
    libcamera::ControlList metadata;
    std::string filename;
    std::string cam_name;
    uint8_t* buffer;
};

方案2:改用智能指针管理内存(更简洁,减少手动内存操作)

使用std::unique_ptr自动管理堆内存,它默认禁用拷贝、支持移动,无需手动编写析构和移动函数:

#include <memory>

class ImageData 
{
public:
    ImageData(std::vector<libcamera::Span<uint8_t>> m, StreamInfo i, libcamera::ControlList met, std::string fil, std::string cam) :
        mem(m),
        info(i),
        metadata(met),
        filename(fil),
        cam_name(cam),
        buffer(std::make_unique<uint8_t[]>(mem[0].size_bytes())) {}
        
    // 无需手动编写析构函数,unique_ptr会自动释放内存
    
    std::vector<libcamera::Span<uint8_t>> mem;
    StreamInfo info;
    libcamera::ControlList metadata;
    std::string filename;
    std::string cam_name;
    std::unique_ptr<uint8_t[]> buffer; // 替换原始指针为智能指针
};

额外检查项

为避免其他潜在问题,建议在ImageData构造函数中添加mem非空判断:

if (mem.empty()) {
    throw std::invalid_argument("ImageData: mem vector cannot be empty");
}

内容的提问来源于stack exchange,提问作者Too Long Din't Read

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:10:26