When does an auto_ptr destruct?

In the following code I am trying to create Widget objects using a WidgetMaker class which is a friend of Widget and is thus able to call its private constructor. Can anyone tell me why the auto_ptr destructs after calling Widget::asString() in the following code? How should I have done 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
#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Widget;
class WidgetMaker {
public:
	Widget* getWidget(const string& name);
private:
};

class Widget {
friend class WidgetMaker;
public:
	const string& asString(){return name_;}
	virtual ~Widget();
private:
	Widget(){};
	string name_;
};

Widget* WidgetMaker::getWidget(const string& name){
	auto_ptr<Widget> pWidget(new Widget);
	pWidget->name_ =  name;
	return pWidget.get();
}

Widget::~Widget(){
	cout << "Widget destructing..." << endl;

}

int main() {
	WidgetMaker maker;
	Widget* pWidget = maker.getWidget("My Widget");

	const string widgetName = pWidget->asString();
	cout << "Name: " << widgetName << endl;

	return 0;
}


The output I get is:

Widget destructing...
Name: 

which shows that pWidget gets destroyed in the Widget::asString() function and so widgetName never gets populated.
It doesn't get destroyed in asString, it is destroyed in getWidget.
At the end of the function pWidget goes out of scope and is destroyed, which also destroys the Widget.
Yes, big bug.

Line 27 should be

return pWidget.release();

if you don't want the temporary widget object destroyed (which you don't since you are returning a pointer to it).
Thanks for your replies. It was a very simple error that I made. In fact it was only after stripping down my original code and rewriting it in terms of Widgets etc for this post that I finally realised it was to do with auto_ptr. My original "Widget" class contained a lot of other members which were mainly inbuilt types (and thus did not get destructed). This meant that the errors I was getting didn't arise until much later when the memory started getting overwritten. NASTY!

Actually I don't want to release the pointer. Otherwise there is no point in using a smart pointer in the first place since the caller would have to remember to delete it. Instead I think I really need to return the object as an auto_ptr. Here is what I hope is the correct code:

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
#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Widget;
class WidgetMaker {
public:
	auto_ptr<Widget> getWidget(const string& name);
};

class Widget {
friend class WidgetMaker;
public:
	const string& asString(){return name_;}
	virtual ~Widget();
private:
	Widget(){};
	string name_;
};

auto_ptr<Widget> WidgetMaker::getWidget(const string& name){
	auto_ptr<Widget> pWidget(new Widget);
	pWidget->name_ =  name;
	return pWidget;
}

Widget::~Widget(){
	cout << "Widget destructing..." << endl;

}

int main() {
	WidgetMaker maker;
	auto_ptr<Widget> autoPtrWidget = maker.getWidget("My Widget");
	Widget* pWidget = autoPtrWidget.get();

	const string widgetName = pWidget->asString();
	cout << "Name: " << widgetName << endl;

	return 0;
}


My output now looks like this:

Name: My Widget
Widget destructing...
P.S. I realised it was necessary for me to do this:
1
2
3
4
	...
	auto_ptr<Widget> autoPtrWidget = maker.getWidget("My Widget");
	Widget* pWidget = autoPtrWidget.get();
	...

rather than:
1
2
3
	...
	Widget* pWidget = maker.getWidget("My Widget").get();
	...

otherwise the auto_ptr passed back still gets destroyed...
Topic archived. No new replies allowed.