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

C++创建子类对象数组并调用子类成员函数的异常问题排查

问题分析与解决办法

看起来你遇到的问题是调用子类xiAPIplusCameraOcv的GetNextImageOcvMat()成员函数时,对象意外触发析构函数,导致相机被关闭。结合你的代码和描述,我整理了几个最可能的原因和对应的解决思路:

1. 未捕获的异常触发栈展开

最常见的原因是GetNextImageOcvMat()函数内部抛出了非xiAPIplus_Exception类型的异常,比如OpenCV的cv::Exception或者标准库异常,而你的catch块只捕获xiAPIplus_Exception,导致异常向上传播,触发栈展开——此时try块中的局部变量(包括cam数组)会被销毁,所有相机对象的析构函数都会被调用,表现为你看到的“调用函数后析构触发”。

解决方法

扩展catch块,捕获更多类型的异常,同时打印详细错误信息,定位问题根源:

catch (xiAPIplus_Exception& exp) {
    printf("xiAPI Error:\n");
    exp.PrintError();
} catch (cv::Exception& exp) {
    printf("OpenCV Error:\n%s\n", exp.what());
} catch (std::exception& exp) {
    printf("Standard Error:\n%s\n", exp.what());
} catch (...) {
    printf("Unknown Error occurred!\n");
}

2. 意外的对象拷贝导致临时对象销毁

如果父类xiAPIplus_Camera包含不可拷贝的资源(比如相机句柄、指针),而子类xiAPIplusCameraOcv没有显式禁用拷贝构造和赋值操作,可能在某些隐式场景下触发对象拷贝(虽然你的代码中没有直接拷贝,但某些函数调用可能隐含拷贝),临时拷贝的对象被销毁时会打印析构日志,让你误以为原对象被销毁。

解决方法

在子类中显式禁用拷贝构造和赋值操作,避免意外拷贝:

class xiAPIplusCameraOcv : public xiAPIplus_Camera {
public:
    xiAPIplusCameraOcv();
    virtual ~xiAPIplusCameraOcv();
    cv::Mat GetNextImageOcvMat();
    cv::Mat ConvertOcvMat(xiAPIplus_Image * input_image);

    // 禁用拷贝构造和赋值
    xiAPIplusCameraOcv(const xiAPIplusCameraOcv&) = delete;
    xiAPIplusCameraOcv& operator=(const xiAPIplusCameraOcv&) = delete;

private:
    // ... 原有成员
};

3. 栈内存损坏导致对象意外销毁

你使用了栈上的对象数组xiAPIplusCameraOcv cam[5];,如果代码中存在数组越界、非法内存访问等问题,可能破坏栈结构,导致对象的生命周期被错误触发(比如提前调用析构函数)。

解决方法

改用堆分配的对象,避免栈内存问题,同时更灵活地管理相机对象:

int main(int argc, char* argv[]) {
    try {
        int n = xiAPIplusCameraOcv().GetNumberOfConnectedCameras();
        std::vector<std::unique_ptr<xiAPIplusCameraOcv>> cam;
        cam.reserve(n);
        
        char sn[100];
        for (int id = 0; id < n; id++) {
            printf("Opening %d. camera ...\n", id + 1);
            auto camera = std::make_unique<xiAPIplusCameraOcv>();
            camera->OpenByID(id);
            camera->GetSerialNumber(sn, 100);
            cam.push_back(std::move(camera));
        }
        
        for (int exp = 0; exp < n; exp++) {
            cam[exp]->StartAcquisition();
            cv::Mat cv_mat_image = cam[exp]->GetNextImageOcvMat();
            cv::imwrite(save_at, cv_mat_image);
            cam[exp]->StopAcquisition();
        }
        // ... 后续代码
    } 
    // ... catch块
}

4. 添加调试信息定位问题

为了明确是哪个对象被销毁,你可以在析构函数和主函数中添加地址打印,确认是否是原相机对象被销毁:

修改析构函数

xiAPIplusCameraOcv::~xiAPIplusCameraOcv(){
    printf("Closing xiAPIplus_Ocv camera at address: %p\n", this);
    cv_mat_image_.release();
}

修改主函数循环

for (int exp = 0; exp < n; exp++) {
    printf("Processing camera at address: %p\n", &cam[exp]);
    cam[exp].StartAcquisition();
    cv::Mat cv_mat_image = cam[exp].GetNextImageOcvMat();
    cv::imwrite(save_at, cv_mat_image);
    cam[exp].StopAcquisition();
}

对比打印的地址,如果析构的地址和当前处理的相机地址一致,说明原对象确实被意外销毁;如果地址不同,则是临时对象的析构,无需担心。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 15:07:49