Satview: Pointer Perfect, Part 3 - The concept of source and sink
(Page 6 of 6 )
Because ownership of resources is transferred from one auto_ptr to another, it is possible to originate allocated resources from a function or to make a function work like a dead-end for allocated resources. When an auto_ptr is returned, the function is known to behave as a source of the data.
std::auto_ptr<MyClass> foo() {
std::auto_ptr<MyClass> pMyObj(new MyClass);
/* perform some operations */
return pMyObj;
}
Every time foo() is called, a new MyClass object is constructed and its ownership is transferred to the caller of this function using the auto_ptr. For example:
void bar() {
std::auto_ptr<MyClass> pObj;
for (int idx=0; idx<10; ++i)
pObj = foo();
}
In the example above, MyClass is allocated 10 times and destructed 10 times. The allocation takes place in foo() and the destruction happens in the scope of the for-loop within bar(). The ownership of MyClass is transferred to pObj in every loop and we know that, since the assignment operator releases any previous resource owned by the current auto_ptr, MyClass gets properly destructed 9 times. Yes, 9 times, because at the end of bar() pObj will still be the owner of a MyClass. But as we leave the scope of the function, that last MyClass resource will be freed as well.
When an auto_ptr is passed as an argument to a function, the function will obtain ownership of the auto_ptr and behave as a sink of the data.
void foo(std::auto_ptr<MyClass> pMyObj);
Every time foo is called, it will free the resource held by the auto_ptr:
void bar() {
for (int idx=0; idx<10; ++idx) {
std::auto_ptr<MyClass> pMyObj(new MyClass);
foo(pMyObj);
}
}
So in the example above, MyClass gets constructed 10 times by bar() and is freed 10 times in foo(), simply because the auto_ptr that is passed into foo() is not being passed back to bar(). As soon as it loses scope in foo(), the MyClass resource allocated in bar() gets released inside foo().
Often a function takes a const reference to the object passed into it when they copy that object internally (this happens in the STL with containers for example):
template<class T> void container::insert( T const &value );
An auto_ptr modifies the object with which it is being initialized. So when insert tries to make a copy of value, an auto_ptr will try to modify value from which it is prohibited by the const modifier. This is actually good behaviour; imagine what would happen if you could validly store auto_ptrs inside a container. The agony of having ownership transferred to containers as you are filling them, then taking back ownership as you are using them, would make it just a too big a headache to keep track of what could happen in that situation!
You understand now that the auto_ptr is not suitable for every kind of smart pointer you can think of. In fact, if you don’t understand how the ownership semantics work, I think you should steer away from it. What if you do want to store smart pointers in STL containers? What if you want a smart pointer that you can reset with another resource and that destroys itself when it goes out of scope (no a const std::auto_ptr<T> won’t suffice here)?
The boost (www.boost.org) library extends the STL for that reason with smart pointers of its own (it is peer-reviewed and some of the boost libraries might be included in the STL by the C++ Standards Committee) and we will take a look at them in the next article.
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |