Smart pointers

Feb 23, 2016 at 11:10am
Hi,

Please have a look at the code below. Is this a smart pointer?
If so, why the first object, p1, is dangling at the end of the code? (That is p2 is deleted by the destructor but p1 remains, why?)

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
43
44
45
46
47
#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;
	
	return 0;
}

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

catch (...) {
	cerr << "Exception occurred.\n";
	return 1;
}
Last edited on Feb 23, 2016 at 11:14am
Feb 23, 2016 at 11:16am
If so, why the first object, p1, is dangling at the end of the code? (That is p2 is deleted by the destructor but p1 remains, why?)

What makes you think this is the case?
Feb 23, 2016 at 12:08pm
I think it has sth. do to with scope. If you wrap the code with the pointer in their own block they will get out of scope before main end.

Try 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#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 () 
  {
    cout << "\n** my_auto_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;
    }
    system ("pause");
    return 0;
  }
  catch (...)
  {
    cerr << "Exception occurred.\n";
    system ("pause");
    return 1;
  }  
}
Feb 23, 2016 at 1:06pm
Your question makes no sense.

Both of your custom my_auto_ptr type objects are destructored. In doing so, both of them call delete on the objects you created with new.

As Peter asked, why do you think this isn't happening?
Feb 23, 2016 at 1:13pm
@Moschops,

did you run his code?

When I ran it on my VS 2013 CE the destructor's were not called - added a cout statement in his destructor.
Feb 23, 2016 at 1:32pm
On my VS2015 the destructor is called as expected for both pointers.
Feb 24, 2016 at 6:53am
@Thomas1965: Yes, I agree.
And to me it's not a smart pointer enough, because we need to add a block for every pointer we create.
My compiler is MS VS 2015. And I ran the code through "Run To Cursor" mode.
Thanks to all.
Feb 24, 2016 at 7:48am
Best way to find out if you're destructor is being called for both objects?

Do this:

Add a cout statement saying "Destructing auto_ptr" inside your destructor. Next, run your program from the COMMAND PROMPT in windows. This console won't close and you'll get to see the destructor output. You should see two destructor lines, indicating that it was called twice - once for each auto_ptr.

Try it.

Joe
Concord Spark Tutor
sparkprogrammer@gmail.com
Feb 24, 2016 at 10:16am
@Thomas1965

I cannot imagine that such a basic C++ concept like destructor doesn't work correctly with any recent compiler (including VS 2013).
Feb 24, 2016 at 10:37am
@coder777,

I didn't say that it didn't work. I meant that when it went out of scope there that the console was closed already. That's the reason why I added the additional scope to see a result. When using a logfile it clearly show that both destructors were called.
Sorry if I was not clear enough, but English is not my native language.
Feb 24, 2016 at 11:49am
The fundamental concept of C++ is that the destructor is called when an object falls out of the scope where the constructor is called.

That means when an exception arise during or before the constructor is called the destructor isn't called either. Thus it is possible due to an exception that the destructor is not called.
Feb 25, 2016 at 8:29am
You guys, are right. I added the system ("pause"); inside the destructor's body and it showed that the destructor was called for both pointers. Even when I created another object, for this one too, the destructor was called. And also there is no need to add any redundant blocks.
Apparently we cannot only rely on the "Run To Cursor" feature for seeing what is happening. Thanks.
Topic archived. No new replies allowed.