2

C++ OpenCV コードの一部を並列化する準備をしています。セグメンテーション違反に遭遇しましたが、何が起こっているのか理解できません。

コードは次のとおりです。

class ExhaustiveComparisonMT
{
    vector<Mat> *m_sigs;
    Mat *m_dist;
public:
    ExhaustiveComparisonMT(vector<Mat> sigs, Mat dist)
    {
        m_sigs = &sigs;
        m_dist = &dist; // gdb breakpoint 1 here
    }

    void operator() (size_t last_row, size_t last_col) const
    {
        Mat diff = (*m_sigs)[0].clone(); // segfault happens here, gdb breakpoint 2 here
        for (size_t i = 0; i != last_row; ++i)
        for (size_t j = 0; j != last_row; ++j)
        {
            cv::absdiff((*m_sigs)[i], (*m_sigs)[j], diff);
            m_dist->at<double>(i, j) = cv::sum(diff).val[0];
        }
    }
};

void
exhaustive_comparison(vector<Mat> sigs, Mat dist)
{
    size_t width = sigs.size();
    ExhaustiveComparisonMT ecmt(sigs, dist);
    ecmt(width, width);
}

基本的に、行列のベクトルがコンストラクターに渡されます。ベクトルへのポインターはメンバー変数として保持されるため、ベクトルは で再度アクセスできますexhaustive_comparison。ただし、その関数はベクトルの最初の要素にアクセスしようとしてつまずきます。

2 つのブレークポイントを配置して、gdb の問題を診断しようとしました (コードを参照)。ブレークポイント 1:

(gdb) p (*m_sigs)[0]
$1 = (cv::Mat &) @0x7fffee77d010: {flags = 1124024325, dims = 2, rows = 1, cols = 712, data = 0x624ec0 "", refcount = 0x0, datastart = 0x624ec0 "", dataend = 0x6259e0 "", 
  datalimit = 0x6259e0 "", allocator = 0x0, size = {p = 0x7fffee77d018}, step = {p = 0x7fffee77d060, buf = {2848, 4}}}

したがって、最初の要素は正しくアクセスされています。次に、ブレークポイント 2 に移動して、同じことを試します。

(gdb) p (*m_sigs)[0]
$2 = (cv::Mat &) @0x7fffee77d010: <error reading variable>

最初の要素はもうアクセスできないようです! そのアドレスは同じ (0x7fffee77d010) です。何が起きてる?

最後に、前に進むと、次のようになります。

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a0dd50 in cv::Mat::copyTo(cv::_OutputArray const&) const () from /usr/local/lib/libopencv_core.so.2.4

OpenCV は最初の要素にアクセスしてクローンを作成しようとしますが、失敗します。

コンストラクターで最初の要素にアクセスできるのに、exhaustive_comparisonメンバー関数ではアクセスできないのはなぜですか?

4

1 に答える 1

5
ExhaustiveComparisonMT(vector<Mat> sigs, Mat dist)
{
        m_sigs = &sigs;
        m_dist = &dist; // gdb breakpoint 1 here
}

変数sigsdistコピーして渡しています。つまり、変数の有効期間はこの関数に制限されています。

それらのアドレスを取得して後で使用しようとすると、不明なデータを指すことになります。これは、この関数を終了すると、これらのオブジェクトが破棄され、それらのアドレスが後で別の目的に使用されるためです。

パラメータとして渡したオブジェクトのアドレスが必要な場合は、参照を使用する必要があります。これにより、元のオブジェクトのアドレスを実際に取得できます。もちろん、これは関数に左辺値を渡していると仮定して機能し、その間にそれらは破棄されません。

ExhaustiveComparisonMT(vector<Mat> &sigs, Mat &dist)
{
        m_sigs = &sigs;
        m_dist = &dist; // gdb breakpoint 1 here
}
于 2013-04-09T05:26:31.423 に答える