【问题标题】:Creating cv::Ptr cause an exception at the end of the application在应用程序结束时创建 cv::Ptr 会导致异常
【发布时间】:2021-05-18 07:12:50
【问题描述】:

我正在使用 openCV arUco 标记来检测一些标记。 所以我生成了预定义的字典并将其保存在一个文件中。 然而aruco::detectMarkers 只能得到Ptr<aruco::Dictionary>。所以我创建了一个Ptr<aruco::Dictionary> 对象并将对象本身的地址发送给构造函数。 这导致应用程序结束时出现异常。 我该如何解决?

这是我的(简化的)代码:

#include <opencv2/highgui.hpp>
#include <opencv2/aruco/charuco.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

aruco::Dictionary ReadDictionaryFromFile(std::string fileName)
{
    cv::FileStorage fileStorage(fileName, cv::FileStorage::READ);
    Mat bytesList;
    int markerSize;
    int maxCorrectionBits;
    fileStorage\["markerSize"\] >> markerSize;
    fileStorage\["maxCorrectionBits"\] >> maxCorrectionBits;
    fileStorage\["bytesList"\] >> bytesList;
    fileStorage.release();
    aruco::Dictionary dictionary = cv::aruco::Dictionary(bytesList, markerSize, maxCorrectionBits);

    return dictionary;
}

int main(int argc, char *argv\[\])
{
    //Detector parameters:
    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
    
    //This works but I am afraid will generate another dictionary on another machine
    //Ptr<aruco::Dictionary> dictionary = aruco::generateCustomDictionary(1, 4);

    //This works but generate exception when app is terminated
    aruco::Dictionary dictionaryTemp = ReadDictionaryFromFile("Dictionary.yml");
    Ptr<aruco::Dictionary> dictionary = cv::Ptr<aruco::Dictionary>(&dictionaryTemp);

    while (true)
    {
        if (camera.grab(image) != SUCCESS)
        {
            cout << "error on grab()" << std::endl;
            return 0;
        }
        
        vector< int > ids;
        vector< vector< Point2f > > corners, rejected;
        vector< Vec3d > rvecs, tvecs;

        // detect markers and estimate pose
        aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);

        aruco::drawDetectedMarkers(image, corners, ids);

        imshow("out", image);
        char key = (char)waitKey(1);
        
        if (key == 'q')
        {
            break;
        }
    }

    return 0;
}

这是一个例外:

【问题讨论】:

    标签: c++ opencv exception memory aruco


    【解决方案1】:

    根据 cv::Ptr 文档:

    具有共享所有权的智能指针的模板类。

    Ptr 伪装成指向 T 类型对象的指针。然而,与普通指针不同的是,一旦指向它的所有 Ptr 实例都被销毁,该对象将被自动清理。

    您正在堆栈上创建一个对象,然后您正在使用它来构造智能指针。智能指针根本不拥有该对象。

        aruco::Dictionary dictionaryTemp = ReadDictionaryFromFile("Dictionary.yml");
        Ptr<aruco::Dictionary> dictionary = cv::Ptr<aruco::Dictionary>(&dictionaryTemp);
    

    在范围的末尾,在您的情况下,它是主要的末尾,dictionaryTemp 将超出范围并销毁对象。

    之后,智能指针字典也将超出范围,但现在指针悬空,几乎任何事情都可能发生。

    修改您的代码以赋予智能指针真正的所有权:

    Ptr<aruco::Dictionary> ReadDictionaryFromFile(std::string fileName)
    {
        ...
        return cv::Ptr<aruco::Dictionary>(
             new cv::aruco::Dictionary(bytesList, markerSize, maxCorrectionBits));
    }
    

    出于与异常安全相关的考虑,在现代 C++ 中编写关键字 new 很少见,最佳实践要求使用名为 std::make_shared 的包装函数(与 std::shared_ptr 一起使用,有类似的函数对于其他智能指针)。我不熟悉 cv::Ptr 并且我无法找到它的等价物。但值得留意。

    熟悉 RAII https://en.cppreference.com/w/cpp/language/raii 和异常安全 https://www.stroustrup.com/except.pdf

    另外,您可能想熟悉不同类型的智能指针Smart pointers: who owns the object?

    【讨论】:

      猜你喜欢
      • 2014-02-17
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 2022-06-21
      • 2014-11-25
      • 2014-10-26
      • 2014-09-03
      • 1970-01-01
      相关资源
      最近更新 更多