Throw and Catch

Hi all,

The following code is a simple auto_ptr class supporting only a few operators. I tried to provide the code with some eception handlers that seem to be required for such codes in a good program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <vector>
using namespace std;

template <class T> class my_auto_ptr {
	T* myptr;
public:
	my_auto_ptr(T* ptr = 0) : myptr(new T(*ptr)) { }

	~my_auto_ptr() { if (myptr) delete myptr; 
	                 else throw; }

	T* operator ->() const { if (myptr) return myptr; else throw; }
	T& operator* () const { if (*myptr) return *myptr; else throw; }

	T* release() {
		T* rptr = myptr;
		myptr = 0;
		return rptr;
	}
};

//----------------------------------

int main() try {
	my_auto_ptr<vector<int> > p1(new vector<int>(4, 5));
	cout << p1->size() << endl;

	my_auto_ptr<int> p2(new int(6));
	cout << *p2 << endl;
	p1.release();
	
	return 0;
}

//-------------------------------

catch (...) {
	cerr << "Exception occurred";
	return 1;
}


I get the "Unhandled exception" error message in line 11 (of the code).

myptr is created by new and deleted by delete. It seems reasonable.
Is the way I used throw and catch for handling exceptions right? (I don't think so!)
What is the reason I get that exception error message please? (I think the incorrect using of exception handlers!)

Would anybody clear up the issue please? :-)

Last edited on
There are several things

throw; is used to rethrow, that is, you catch the exception, handle as you can, and then propagate it upwards.
To actually throw, you need to especify what are you throwing. By instance throw std::runtime_error("some helpful message");


Don't throw from destructors
https://isocpp.org/wiki/faq/exceptions#ctor-exceptions
https://isocpp.org/wiki/faq/exceptions#dtors-shouldnt-throw


Leaks all over the place.
your constructor is allocating dynamically myptr(new T(*ptr)), yet when creating the variable you are already doing that my_auto_ptr<int> p2(new int(6));. So 2 allocations, but only 1 delete.
Also, ¿what would happen if you my_auto_ptr<Base> foo( new Derived() );?


Missing copy constructor and assignment operator. Although you probably code them later, ¿right?
Till then, you may mark them as non-existant my_auto_ptr( const my_auto_ptr &) = delete;


¿Why do you consider an error for `myptr' to be null in the destructor?


1
2
3
4
5
6
T& operator* () const {
  if (*myptr) //dereferencing, so T must be able to convert to bool
    return *myptr;
  else
    throw; //¿is it an error for the object pointed to be false?
}

Last edited on
Thanks for making info on throw.
The resources you offered are very great. I didn't read them all, but I figured out that (for the time being) I should not use an exception thrower inside the destructor. I will read them some time later :-)

About the two allocations, I agree with you.

To be honest, I was too worry about using delete in its correct way and didn't notice the down part of the code!

I don't use any more functions inside the class because (for this special case) I'm to use only a constructor, destructor, ->, *, and release() for that. :-)

This is the new one. What do you think of this? :-)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <vector>
using namespace std;

template <class T> class my_auto_ptr {
	T* myptr;

public:
	my_auto_ptr(T* ptr = 0) : myptr(ptr) { }

	~my_auto_ptr() { delete myptr; }

	T* operator ->() const { if (myptr != nullptr)  return myptr; 
	                         else throw runtime_error(""); }
	T& operator* () const {	if (myptr != nullptr)  return *myptr;
	                        else throw runtime_error(""); }
	T* release() {
		T* rptr = myptr;
		myptr = 0;
		return rptr;
	}
};

//----------------------------------

int main() try {
	my_auto_ptr<vector<int> > p1(new vector<int>(4, 5));
	cout << p1->size() << endl;

	my_auto_ptr<int> p2(new int(6));
	cout << *p2 << endl;
	p1.release();
	
	return 0;
}

//-------------------------------

catch (...) {
	cerr << "Exception occurred\n";
	return 1;
}


PS: If I used p2.release() in the line 32, the first object (p1) would be dangled!
Apparently, the destructor works only on the last object created for deleting!
If I used p2.release() in the line 32, the first object (p1) would be dangled!
No? They are not related.

Apparently, the destructor works only on the last object created for deleting!
What?
.release() would remove the ownership and transfer it to the client code.
In your case you are not even catching the returned value, so can't delete it, so leak.


I would like to know how did you test your claims in the PS.
coder777wrote:
No? They are not related.
I experienced that by running the code by VS 2015 in Debug mode and using the Run To Cursor feature.
When I used p2.release() instead of p1.release() in my code, the p2 was remained even after executing the destructor!
Of course I think, all the resources reserved in a program will be brought back to the memory when a program terminates, by the operating system.

coder777wrote:
What?
What thing invokes the destructor at the end of the code? (Apparently the this which is pointing to the last object created!)

@ne555,
Sorry I didn't understand what you meant.

Last edited on
Kubani wrote:
What thing invokes the destructor at the end of the code? (Apparently the this which is pointing to the last object created!)

You have a misunderstanding here. this points to the object that the current function was called on. If you call obj1.f() this will point to obj1 inside the function f. When the object was created is not relevant.

If you don't use delete on something that was created with new the destructor will not be invoked.
Last edited on
Topic archived. No new replies allowed.