I was studying about the RAII mechanism in C++ which replaces the finally
of Java. I wrote the following code to test it:
void foo(int* arr) {
cout << "A" << endl;
throw 20;
cout << "B" << endl;
}
class Finally {
private:
int* p;
public:
Finally(int* arr) {
cout << "constructor" << endl;
p = arr;
}
~Finally() {
cout << "destructor" << endl;
delete(p);
}
};
int main()
{
int * arr = new int[10];
new Finally(arr);
try {
foo(arr);
} catch (int e) {
cout << "Oh No!" << endl;
}
cout << "Done" << endl;
return 0;
}
I want to free the memory which I used for arr
so I set a new class Finally
which saves the pointer to the array and when it exits the scope it should call the destructor and free it. But the output is:
constructor
A
Oh No!
Done
No call for the destructor. It also does not work when I move the body of main
to some other void method (like void foo()
). What fix should I do to achieve the desired action?
That's because the object you create with new Finally(arr)
doesn't really gets destructed in your program.
Your allocation of the object just throws the object away immediately, leading to a memory leak, but more importantly it's created outside the scope of the try and catch.
For it to work you have to do something like
try {
Finally f(arr);
foo(arr);
} catch (int e) {
cout << "Oh No!" << endl;
}
That would create a new object f
in the try, which will then get destructed when the exception is thrown (as well as when it goes out of scope of the try
if no exception is thrown).
You're assuming C++ works liked Java. It doesn't, so there are actually a few things wrong in your code
The statement
new Finally(arr);
dynamically allocates a Finally
, but it is NEVER released in your code. Hence its destructor is never called.
Instead do
Finally some_name(arr);
This will invoke the destructor of Finally
- at the end of main()
- which will give the output your expect.
However, the second thing wrong is that the destructor of Finally
does delete (p)
which gives undefined behaviour, since p
is the result (in main()
) of new int [10]
. To give the code well-defined behaviour, change delete (p)
to delete [] p
.
Third, with the two fixes above, you are not using RAII. RAII means "Resource Acquisition Is Initialisation", which is not actually what your code does. A better form would be to initialise p
using a new expression in Finally
s constructor and release it with a correct delete
expression in the destructor.
class Finally
{
private:
int* p;
public:
Finally() : p(new int [10])
{
cout << "constructor" << endl;
};
~Finally()
{
cout << "destructor" << endl;
delete [] p;
};
int *data() {return p;};
};
AND replace the first two lines of your main()
with a single line
Finally some_name;
and the call of foo()
with
foo(some_name.data());
More generally, stop assuming that C++ works like Java. Both languages work differently. If you insist on using C++ constructors like you would in Java, you will write terribly buggy C++ code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.