In Stroustrup's version, if anything throws an exception, the vector is left in it's original state. The assignment either works completely or does nothing, and that's a good thing. The only bad thing is that it will leak memory if the new succeeds but, say one of the assignments throws.
On the other hand, your version will leave *this in an inconsistent state of anything throws an exception because you delete element at the very beginning an the vector isn't consistent again until the very last assignment.
There's another nice effect of Stroustrup's version that hasn't been mentioned: if you assign a vector to itself, it resizes the buffer to match the exact size of the vector. Okay, the vector as written doesn't let you erase items, but if it did, this could be important:
// Populate v
// Now erase 500 elements in v.
v = v; // Stroustrup's methoid resizes the buffer to 500.
|It return nothing and the control goes out of the function to the assignment. So nothing happens which what we expect when we assign an object to itself. Not true?|
Here's the problem.
Vector a(10), b(10), c(10);
a = b = c; // okay
a = b = b; // Oops. (b = b) doesn't return anything, so you try to assign garbage to a.
|please tell me what the problem is with my prior code and why still we need that pointer p in it:|
Your code works most of the time, but Stroustrup's works in some error conditions where yours fails.
|On line 24: if we can't allocate memory by new and can't copy the right hand object (a) to the left one (&this), why destroying it!?|
It's a judgement call, but I'd agree with you. More importantly (to me) is that malibor's version doesn't give any indication to the caller that the problem occurred, so the caller will happily go on, assuming that the assignment succeeded when in reality, it cleared the vector. That's why I think it's better to leave the vector in it's original state and let the caller deal with the exception, which is exactly what Stroustrup did.
|Isn't routine to handle an exception the following way in catches, please?|
Maybe. Maybe not. The point is who are you to tell the application writer what should happen to their program?
Maybe they want to abort. Maybe they don't. Shouldn't that be their decision?
Also, and probably far more important, your catch block has this:
cerr << ex.what() << "\n";
What makes you think that this code won't try to allocate memory itself?
And herein lies the great difficulty of dealing with out-of-memory conditions. Unless you're 100% certain that your recovery code won't attempt to allocate even 1 byte of memory, you run the risk of getting another allocation exception. For this reason, the only safe way I've seen to deal with out of memory is to allocate a reserve when the program starts. If you run out of memory, free the reserve immediately and then hobble your way through whatever cleanup code is needed.
Where I work, we made a deliberate decision to not
check for out-of-memory conditions. It would make the code twice as big and chances are excellent that we wouldn't handle the problem right anyway. Instead, we check for low memory conditions at strategic points in the code and exit cleanly if memory is low. This works well. Years go by without ever getting an actual out-of-memory condition. I realize that this sounds like saying "Stroustrup's method doesn't matter," but I'm really just saying that this is how my company decided to handle the situation. Stroustrup's method is more robust, and that's always good.
|Safe code is far more important than performance, you don't sacrifice safe code for performance. lazy-ness to write a few lines more is out of question.|
It's a real shame that they don't seem to teach error checking in schools. In the real world, you always need to check for errors. Some quote from me and coworkers on the subject:
"Jmon (a program) processes errors. Doing useful work just a side gig."
"The biggest perofrmance boost is going from not working, to working."
"Code can run arbitrarily quickly if correctness isn't a factor."