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

C++17中从std::queue获取含cv::Mat的FRAME结构体是否正确?

问题描述

我尝试用std::queue和OpenCV实现一个IP摄像头帧抓取类,最多缓存10帧供其他类获取。相关代码如下:

/* Camera.cpp */
struct FRAME
{
    cv::Mat  Img;
    uint64_t Time;
    bool     ReadError;
};

class Camera
{
    std::queue<FRAME>    m_buffer;
    std::mutex           m_buffer_mutex;
    ...
};

void Camera::threadFunc_get_stream_from_camera()
{
    while (true)
    {
        FRAME frame;

        ... // 读取帧的逻辑(如果cv::read失败则跳过存入缓存的步骤)

        m_buffer_mutex.lock();

        while (m_buffer.size() >= 10)
            m_buffer.pop();

        m_buffer.push(frame);

        m_buffer_mutex.unlock();
    }
}

FRAME Camera::grab()
{
    std::unique_lock ulock(m_buffer_mutex);

    FRAME frame;
    if (m_buffer.empty() == false)
    {
        frame = m_buffer.front();
        m_buffer.pop();
        return frame;
    }
}

/***************/
/* Testing.cpp */

int main()
{
    // Camera* cam ..
    ...

    while (true)
    {
        auto frame = cam->grab();

        if (frame.Img.data == nullptr || frame.Time == 0)
            continue;

        ... // 帧图像处理逻辑
    }
}

程序稳定运行了约3天,没有异常或内存问题,但我有个疑问:grab()函数返回非指针类型的FRAME是否正确?我用的是C++17,知道结构体里的uint64_t和bool拷贝没问题,但不确定cv::Mat的情况。另外我不想用生产者-消费者模式,因为不想让Camera类依赖测试类的代码。


解答

1. 返回非指针类型FRAME是完全正确的

你担心的cv::Mat拷贝问题其实不用多虑:

  • cv::Mat内部采用引用计数机制,默认的拷贝构造/赋值操作都是浅拷贝,只会复制矩阵头(包含指向像素数据的指针、尺寸、类型等信息),不会复制实际的像素内存,拷贝成本极低。
  • 当最后一个持有该数据的cv::Mat对象被销毁时,才会自动释放像素内存,不会出现内存泄漏。
  • C++17对结构体的拷贝语义没有特殊限制,FRAME里的uint64_t、bool都是基本类型,拷贝行为完全可靠。

2. 当前代码的潜在小问题

虽然运行稳定,但有几个细节可以优化:

  • grab()函数在缓存为空时,会返回一个默认构造的FRAME(Img.data为nullptr、Time为0),这和你测试代码里的判断逻辑匹配,但最好在函数里明确处理这种情况,比如添加注释或者保证返回值的一致性。
  • 用std::lock_guard替代手动调用lock()/unlock()更安全:在threadFunc_get_stream_from_camera()中,如果push()之前抛出异常,手动解锁的代码可能不会执行,而std::lock_guard会在作用域结束时自动释放锁,避免死锁风险。修改后的生产者逻辑:
    void Camera::threadFunc_get_stream_from_camera()
    {
        while (true)
        {
            FRAME frame;
    
            ... // 读取帧的逻辑
    
            std::lock_guard<std::mutex> lock(m_buffer_mutex);
            while (m_buffer.size() >= 10)
                m_buffer.pop();
            m_buffer.push(frame);
        }
    }
    

3. 关于生产者-消费者模式的顾虑

你的顾虑是合理的——不需要让Camera类依赖业务逻辑(测试类)。当前的“生产者主动填充缓存,消费者按需抓取”的模式完全没问题,不属于需要耦合业务的典型生产者-消费者实现。如果后续需要更灵活的控制(比如缓存满时阻塞生产者),可以考虑用std::condition_variable,但这也不需要让Camera类依赖测试类,只需要在Camera内部封装条件变量的逻辑即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:16:12