0

このopencvの例では、(ポインターの代わりに)単純な変数imgを作成してから、関数のパラメーターで単純なポインターを使用しなかったのはなぜですかcvReleaseImage(ここでは、パラメーターで二重ポインターを使用します。ポインタのアドレスを再渡します:) &img

IplImage* img = NULL; 
img = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
cvReleaseImage (&img);

また、関数で単純なポインターを使用する場合、ポインターに別*のポインターを追加することで、ポイントされた値を変更できます。

例えば ​​:

function random(int* pointer, int* pointer2){
    *pointer = *pointer2 / 2;
}

したがって、ダブルポインターを使用して、これを実行する必要がありますか?:

function random(int** doublepointer, int* pointer2){
    **doublepointer = *pointer2 / 2;
}

ご協力いただきありがとうございます

4

5 に答える 5

2

シンプル:cvLoadImage()名前が示すように、イメージ全体をメモリにロードし (10MB のファイルを考えてください) IplImage*、イメージ データがメモリ内のどこにあるかを示す を返します。

IplImage代わりに が返された場合、アプリケーションはさらに 10MB のメモリを割り当てて、プログラムのメモリにデータを複製する必要があるため、これは非常に便利です。したがって、データのメモリ アドレスを含むポインターを返すことは、実際には非常に賢明な設計上の決定です。

cvReleaseImage()このデザインを反映するために、ダブル ポインターを受け取ります。OpenCV v2.3 ソース コードをダウンロードすると、次の場所で実装を確認できますmodules/core/src/array.cpp

2979 CV_IMPL void
2980 cvReleaseImage( IplImage ** image )
2981 {
2982     if( !image )
2983         CV_Error( CV_StsNullPtr, "" );
2984 
2985     if( *image )
2986     {
2987         IplImage* img = *image;
2988         *image = 0;
2989 
2990         cvReleaseData( img );
2991         cvReleaseImageHeader( &img );
2992     }
2993 }

メモリ リソースの実際の解放は、他の 2 つのヘルパー関数によって行われることは明らかです。これらの関数は、ある時点でcvFree()メモリを解放するために呼び出します。

cvReleaseImage()ただし、@Nikolai による共有の単純化は正しいです。

編集:あなたのコメントに答えるために。

へのポインターを割り当てて0malloc()も、 /で予約されたメモリの割り当てが解除されることはありませんnew。ポインターが別の場所を指すようになるだけで、この場合はどこにもありません! cvReleaseImage (&img)意味を理解しましょう。それはすべてから始まります:

IplImage* img = NULL; 

ポインター宣言は、通常の変数宣言と同じことを行います。データを格納するために一定量のメモリを割り当てます。上記のような (32 ビット アーキテクチャの) ポインター宣言は、他の変数のアドレスを格納するために 4 バイトのメモリを割り当てます。つまり、ポインタ自体は、宣言された関数内で 4 バイトのメモリを消費します。

呼び出しは、ポインターが指しているデータのアドレスではなく、ポインターcvReleaseImage(&img)のアドレスを渡します(ここで A-HA の瞬間)。

それでは、残りのコードを分析しましょう。

2985     if( *image ) // does the original pointer points somewhere?
2986     {
             // img copies the address of the data pointed by it's cousing image 
2987         IplImage* img = *image; 
             // and handles the deallocation procedure from now own using img.

             // By clearing the original pointer,
2988         *image = 0; 
             // OpenCV allows us to test for it's release 
             // after cvReleaseImage() executes. 

2989 
2990         cvReleaseData( img );

2991         cvReleaseImageHeader( &img );
2992     }

したがって、これ*image = 0;は標準的な手順にすぎないため、後で次のように解放が成功したかどうかを確認できます。

cvReleaseImage (&img);
if (img != NULL)
{
  // OOPS! Something went wrong, memory was not released!
} 
于 2012-03-22T13:37:17.520 に答える
1

ここでのアイデアは、次のcvReleaseImage()ようなことができると思います。

void cvReleaseImage( IplImage** ppimg ) {
    /* ... */
    free( *ppimg );
    *ppimg = NULL;
}

つまり、メモリを解放し、元のポインタを消去します。

于 2012-03-22T13:24:17.810 に答える
1

ユーザーに表示される実際のポインター (この場合は img) を NULL に設定できるため、削除後に誤って使用されないように、ポインターをポインターに渡すことは、"release" または "free" 関数では非常に一般的です。

そして、ええ、ポインターツーポインターのデータを変更するために二重逆参照するだけですが、括弧を使用することをお勧めします。

(*(*doublepointer)) = (*pointer)/2;

それはちょうど私が思うより素敵に見えます。

于 2012-03-22T13:24:39.657 に答える
1

最初の質問に関して: IplImage のサイズは、ロードされるまでわからない可能性がありますが、「単純な変数」のサイズはコンパイル時にわかっている必要があります。

于 2012-03-22T13:25:12.013 に答える
0

関数 cvLoadImage は IplImage へのポインターを返すため、ローカルで定義された IplImage を使用することはできません。

IplImage* cvLoadImage( const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR );

cvReleaseImage には、IplImage 構造体へのポインターのアドレスが必要です。これにより、構造体が削除されたときにポインターを NULL 値に設定できるため、削除されたオブジェクトが誤って使用されることはありません。

于 2012-03-22T13:46:49.420 に答える