Trying to understand this article on why auto_ptr has been deprecated
-
I was reading this article, and I'm trying to understand a point that the author is trying to make. Bartek's coding blog: Smart pointers gotchas[^] class Test { public: Test():m_value(0) { std::cout << "Test::Test" << std::endl; } ~Test() { std::cout << "Test::~Test destructor" << std::endl; } int m_value; }; typedef std::auto_ptr TestAutoPtr; typedef std::unique_ptr TestUniquePtr; typedef std::shared_ptr TestSharedPtr; void doSomethig(TestAutoPtr myPtr) { myPtr->m_value = 11; } void AutoPtrTest() { TestAutoPtr myTest(new Test()); doSomethig(myTest); myTest->m_value = 10; } The author says this will crash. It seems that when myTest is instantiated, there is an auto_ptr object that now exists as a member of myTest, pointing to a heap instantiation of Test. Then when doSomethig() is called the *value* of the pointer is passed (i.e., the address of that heap Test object), and a new auto_ptr object, myPtr, is created, with its value set to the address of that Test object. And then after doSomethig() finishes, myPtr is destroyed, but since it is an auto_ptr, that destruction will delete the object that has the address of its value (i.e., the Test object). So, when a dereference of the myTest object (i.e., an auto_ptr object) is attempted, the Test object is no longer there, and hence an error that is as per trying to dereference an uninitialized (or perhaps null?) pointer. Is my explanation accurate?
-
I was reading this article, and I'm trying to understand a point that the author is trying to make. Bartek's coding blog: Smart pointers gotchas[^] class Test { public: Test():m_value(0) { std::cout << "Test::Test" << std::endl; } ~Test() { std::cout << "Test::~Test destructor" << std::endl; } int m_value; }; typedef std::auto_ptr TestAutoPtr; typedef std::unique_ptr TestUniquePtr; typedef std::shared_ptr TestSharedPtr; void doSomethig(TestAutoPtr myPtr) { myPtr->m_value = 11; } void AutoPtrTest() { TestAutoPtr myTest(new Test()); doSomethig(myTest); myTest->m_value = 10; } The author says this will crash. It seems that when myTest is instantiated, there is an auto_ptr object that now exists as a member of myTest, pointing to a heap instantiation of Test. Then when doSomethig() is called the *value* of the pointer is passed (i.e., the address of that heap Test object), and a new auto_ptr object, myPtr, is created, with its value set to the address of that Test object. And then after doSomethig() finishes, myPtr is destroyed, but since it is an auto_ptr, that destruction will delete the object that has the address of its value (i.e., the Test object). So, when a dereference of the myTest object (i.e., an auto_ptr object) is attempted, the Test object is no longer there, and hence an error that is as per trying to dereference an uninitialized (or perhaps null?) pointer. Is my explanation accurate?
Close but not quite the actual rule goes
An auto_ptr owns the thing/object that it holds a pointer to, and only one auto_ptr may own an object at a time. When you copy an auto_ptr, you automatically transfer ownership from the source auto_ptr to the target auto_ptr. After the copy, only the target auto_ptr owns the pointer and will delete it in due time, while the source is set back to a null state and can no longer be used to refer to the owned object.
The line doSomething(myTest); has an implicit copy because you passed in myTest so the ownership goes into doSomething (passing like that is called an auto_ptr sink operation) and myTest gets the null state as per the description. You can't use it afterwards because it got nulled so it's a guaranteed crash if you try to use the pointer. If you want the auto-pointer back again you should have made doSomething a function returning an auto_ptr and passed it back out, try something like
TestAutoPtr doSomethig(TestAutoPtr myPtr) {
myPtr->m_value = 11;
return myPtr;
}The higher level code becomes
void AutoPtrTest() {
TestAutoPtr myTest(new Test());
myTest = doSomethig(myTest); /* We recopy the auto_ptr ownership back */
myTest->m_value = 10;
}It's just an ownership thing .. only one scope of code can own an autoptr. If you want it back again you need to pass it back otherwise it is assumed it is no longer in use and cleaned up. The actual crash has nothing to do with the cleanup the null of the auto_ptr is automatic when it copied and it's that which causes the crash. You are attributing the crash to the cleanup which isn't the case. If you could somehow keep the autoptr inside doSomething alive say with multitask code you still couldn't use the original pointer because it's value will be null. Just use the debugger put a breakpoint on doSomething and single step into it and look at what happens to the original pointer .. your toast from that point on with the original code because it will go to null :-)
In vino veritas