Opened 21 years ago
Closed 19 years ago
#5 closed Bugs (Fixed)
shared_ptr and self-owning objects
| Reported by: | nobody | Owned by: | Peter Dimov |
|---|---|---|---|
| Milestone: | Component: | smart_ptr | |
| Version: | None | Severity: | |
| Keywords: | Cc: |
Description
Consider following program:
#include <boost/smart_ptr.hpp>
#include <iostream>
class foo {
public:
foo(): m_self(this) { std::cout << "foo
constructor\n"; }
~foo() { std::cout << "foo
destructor\n"; }
void suicide() { m_self.reset(0); }
private:
boost::shared_ptr<foo> m_self;
};
int main() {
foo *foo_ptr = new foo;
foo_ptr->suicide();
}
When linked with Electric Fence this code fails. This
code invokes undefined behavior in reset method of
shared_ptr: when line if (--*pn == 0) {
checked_delete(px); } executes shared_ptr object gets
destroyed and line *pn = 1 acceses already freed
memory.
Why use m_self?
foo's clients share foo by keeping shared_ptr to it.
foo handles some asynchronous event which may render
foo unneeded to itself (network connection close, for
example), but it still may be needed to clients if any.
OTOH, if no clients use foo at the time of the event
then foo needs to destroy itself. This situation is
best modeled with keeping shared_ptr in foo and letting
foo to reset it when foo thinks it's mission is
complete.
The problem with shared_ptr can be solved with small
modification to reset
method:
void reset(T* p=0) {
T *old_px = px;
if ( px == p ) return; // fix: self-assignment
safe
px = p;
if (--*pn == 0) {
*pn = 1;
checked_delete(old_px);
}
else { // allocate new reference counter
try { pn = new long(1); } // fix: prevent leak
if new throws
catch (...) {
++*pn; // undo effect of --*pn above to
meet effects guarantee
px = old_px; // undo effect of px = p above
checked_delete(p);
throw;
} // catch
} // allocate new reference counter
} // reset
operator=(const shared_ptr&) and
operator=(std::auto_ptr&) have the same problem and fix
is very similiar.
Note:
See TracTickets
for help on using tickets.
