|
Re-membering auto_ptr |
#include "xStruct.h" // definition of struct X |
Of course, the program using this class kept crashing intermittently with memory corruption, because I'd violated the Law of the Big Three: Whenever you provide any one of a destructor, copy constructor or assignment operator, you will generally need to provide all three.[1] "So," said I to myself, said I, "I have to handle copying and assignment. Simple... auto_ptr
already has a copy constructor and assignment operator, so I'll use that." (You've heard of the auto_ptr
in the original C++ library, right?)
Since the auto_ptr
automatically deletes the object it points to, all I had to do was change the type of xItem and remove the delete statement in the destructor -- auto_ptr
would take care of the rest, right?
class xWrapper |
Unfortunately, my program was still crashing, this time because it was trying to dereference a null pointer. I had been trying to puzzle out the problem for about half an hour when the Guru, thin as a rail, decided to walk by, carrying a thick book open in one hand. She did that a lot... show up at propitious times, I mean; I think it was some sort of prescient thing. Downright spooky, actually.
"Uh, what're you reading?" I asked her, pointing at her book to deflect attention away from my screen and hoping she would go away.
The Guru blinked. "The writings of Josuttis," she said softly, marked her page, and closed the book. "What's that you have there, young one?"
"I'm having problems with this wrapper class I'm writing," I admitted. "I'm using an auto_ptr
member, but in my test harness its pointer keeps getting reset to null for some reason."
"Show me your writings," the Guru said. I showed her the screen. "Ownership," she said immediately, after barely a glance.
It was my turn to blink.
"Ownership, child; your problem is ownership semantics. No person can serve two masters, and no pointer can serve two auto_ptr
s."
Her words, although certifiably strange, made me realize my mistake. "Okay, right," I nodded. "When you copy an auto_ptr
, the original one relinquishes ownership and gets reset to null. My xWrapper
copy constructor reuses that default behavior, so the original xWrapper
object's auto_ptr
is being reset, and when I try to access it I'm dereferencing a null pointer."
"Correct," the Guru agreed. "You have done well to reuse the true tools of the Standard, but you must take care with them. For xWrapper
, you must still manage xWrapper
copying and assignment yourself."
"But I can't implement them in terms of auto_ptr
's own versions because those won't do the ri--- Oh. I get it. I'll use auto_ptr
's dereference operator to access the owned objects." I quickly wrote out the two functions:
|
"Hey, cool." This, I liked. "I don't even need to check for self-assignment in the assignment operator."
"That is correct."
I should have stopped then and kept my mouth shut, but I wasn't that smart yet. "auto_ptr
sure is easy to misuse. If only it could have told me I was trying to transfer ownership when I didn't expect that to happen..."
"Peace!" interrupted the Guru. "The fault is not with auto_ptr
in this instance. You should have said that you did not want the auto_ptr
to be copied, had that been your desire."
"But how? That's not possible."
"Ah, but it is. Remember the blessings of const-correctness. The way to state that an auto_ptr
is immutable is to make it const
. Had you made the member a const auto_ptr
, the compiler would not have been able to silently perform the copy of the xWrapper
object. Alternatively, had you used something like the strict_auto_ptr
from the Second Revisionist rendering of Cline 30:12, the compiler would not have been able to mistakenly generate incorrect xWrapper
copying and assignment. Of course, in this case making it const
would have been simpler and sufficient."[2]
She reopened her copy of Josuttis and resumed reading as she started to walk away, still talking to me absently, both she and her voice gradually drifting away: "A word of caution, my child... auto_ptr
is a useful tool, but as you have discovered, it is not a panacea. Read and meditate upon Josuttis chapter 4.[3] You must never instantiate a Standard container of auto_ptr
, such as vector<auto_ptr>
, because auto_ptr
does not meet the copying and assignment requirements of the Standard. Furthermore, never attempt to use auto_ptr
to point to an array of objects, for the auto_ptr
's destructor uses non-array delete
to delete the object it owns; for an array of objects, use a vector
instead. The library..."
But then she turned a corner, and was gone. It was only my second day; I wondered, not idly, if I ought to update my résumé while I could still pretend this job had never happened.
- - - - -
"Weird lizard," Jeannine opined, sipping coffee as we exited the Terran local traffic control area, still gaining velocity. "So, did you leave?"
"She was, but no. I'm not sure why," I added honestly. "A few run-ins like that, and I was ready to leave during probation like the rest. I guess he grew on me, though. Didn't you ever work with a quirk like that?"
"Mmm. Some. I suppose."
It was not the last time I would speak with Jeannine about the Guru, or about more pleasant things.
1. M. Cline, G. Lomow, and M. Girou. C++ FAQs, 2nd ed. (Addison-Wesley, 1999).
2. Ibid., FAQ 30.12, pages 426-8.
3. N. Josuttis, The C++ Standard Library (Addison-Wesley, 1999).
Copyright © 2009 Herb Sutter |