in this example from opencv, why didn't we create a simple variable img (instead of a pointer) and then use a simple pointer in the parameter of the function cvReleaseImage
(whereas here, we will use a double pointer in the parameter because we're passing the address of the pointer : &img
) :
IplImage* img = NULL;
img = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
cvReleaseImage (&img);
?
Also, when we use a simple pointer in a function, we can change the pointed value by adding another *
to the pointer :
for example :
function random(int* pointer, int* pointer2){
*pointer = *pointer2 / 2;
}
so with a double pointer, should we do this? :
function random(int** doublepointer, int* pointer2){
**doublepointer = *pointer2 / 2;
}
Thanks for your help
Simple: cvLoadImage()
as the name suggests, loads an entire image to memory (consider a 10MB file) and returns a IplImage*
that says where the image data is located in memory.
This is incredibly useful, because if it returned an IplImage
instead, our application would need to allocate another 10MB of memory, duplicating the data in the program's memory! So returning a pointer with the memory address of the data is actually a very smart design decision.
cvReleaseImage()
receives a double pointer to reflect this design. If you download OpenCV v2.3 source code you can see it's implementation at 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 }
It's clear that the actual release of memory resources is done by 2 other helper functions, which at some point will call cvFree()
to free the memory.
The simplification of cvReleaseImage()
shared by @Nikolai is correct, though.
EDIT: to answer your comment.
Assigning a pointer to 0
will never deallocate the memory that was reserved with malloc()
/ new
, it just makes the pointer point to somewhere else, and in this case, nowhere! Let's understand what cvReleaseImage (&img)
means. It all starts with:
IplImage* img = NULL;
A pointer declaration does the same thing as regular variable declaration: it allocates a certain amount of memory to store some data. A pointer declaration (in a 32bit arch) like the one above allocates 4 bytes of memory to store the address of some other variable. In other words, the pointer itself consumes 4 bytes of memory within the function it was declared.
Calling cvReleaseImage(&img)
passes the address of the pointer and not the address of the data it's pointing to (A-HA moment right here).
Now, let's analyse the rest of the code:
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 }
So doing *image = 0;
is just standard procedure so later we can check for a sucessful deallocation like this:
cvReleaseImage (&img);
if (img != NULL)
{
// OOPS! Something went wrong, memory was not released!
}