-1

I'm new to (boost) shared pointers and I'm trying to test something in a code which I don't want to rewrite bottom up for that purpose.

It turns out, I can solve my problem quite elegantely, when using one of their structs StructA and have the member variable shared_ptr<StructA> foo point to the instance of the struct object.

this is the simplified struct:

struct StructA {
  vars...
  funcs ...
  shared_ptr<StructA> foo;
};

This results in problems of self-reset errors, so I tried to undo the trick, but it doesn't work:

// <their code> (simplified)
StructA lp;
lp.SomePreparation(...);

for-loop () {

  lp.SetSomething(...);
  // my test
  lp.foo.reset(&lp);

  // <their large code section which I'd rather not touch...> 
  // which now works elegantly :)

  // A: doing nothing here, will result in self-reset assertation when 
  //    hitting the `reset(&lp)` above again in the loop. Detailed error below.
  lp.foo.reset(); // B: doing this here, results in glibc double free
  lp.foo.reset(new StructA()); // C: so does this

  // lp.foo = NULL; // what I'd do to a pointer in C.
}

No foo.reset() called: Self-reset error

mybin: include/boost/smart_ptr/shared_ptr.hpp:397: void boost::shared_ptr<T>::reset(Y*) [with Y = StructA, T = StructA]: Assertion `p == 0 || p != px' failed.
Aborted

Calling foo.reset():

*** glibc detected *** mybin: double free or corruption (out): 0x00007fff974b3a30 ***
======= Backtrace: =========
/lib64/libc.so.6[0x342b6760e6]
/lib64/libc.so.6[0x342b678c13]
mybin(_ZN5boost14checked_deleteIN1214StructAEEEvPT_+0x26)[0xdd7dfd]
mybin(_ZN5boost6detail17sp_counted_impl_pIN1214LStructAEE7disposeEv+0x1c)[0xdd8b9a]
mybin(_ZN5boost6detail15sp_counted_base7releaseEv+0x42)[0xcedf54]
mybin(_ZN5boost6detail12shared_countD1Ev+0x27)[0xcee017]
mybin(_ZN5boost10shared_ptrIN1214StructAEED1Ev+0x1c)[0xd2dc38]
mybin(_ZN5boost10shared_ptrIN12C14StructAEE5resetEv+0x5b)[0x149b3a9]
....
Sebastian
  • 1,408
  • 1
  • 20
  • 28

3 Answers3

2

You are trying to point the shared pointer to an instance of an automatic variable. That will result in a call to delete to memory that is not "on the heap". In order to do that, you would have to supply the template argument for a custom deleter (e.g. a do-nothing deleter).

StructA lp; // automatic variable
lp.SomePreparation(...);
...
lp.SetSomething(...);
// my test
lp.foo.reset(&lp); // This is your problem!
...
lp.foo.reset(); // (1)
lp.foo.reset(new StructA()); // (2)

Either (1) or (2) will attempt to delete the object currently being pointed to. For an automatic variable, that is a problem as it is deleted automatically when it goes out of scope.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • yes, I'm aware of that. How would such a *do nothing* deleter work? – Sebastian Nov 30 '13 at 23:50
  • 1
    http://stackoverflow.com/questions/12340810/using-custom-deleter-with-stdshared-ptr A do-nothing deleter simply would not delete anything. – Zac Howland Dec 01 '13 at 02:57
  • thanks again. I see, I'd have to specify the deleter during the declaration of the shared pointer. This would impact the code I don't want to change. For the moment, the workaround in [my answer](http://stackoverflow.com/a/20307254/543411) seems more acceptable. – Sebastian Dec 01 '13 at 10:59
0

Not sure what you actually trying to achieve, but you cannot pass the address of a local variable to a boost::shared_ptr. The boost::shared_ptr destroys its contained object if there are no shared_ptr's pointing to it and ofc destroying a stack based variable is not a good idea.

What are you trying to accomplish?

gast128
  • 1,223
  • 12
  • 22
  • I **can** pass the address of the local variable to the shared pointer in the struct, and the routines labelled `` all work with this trick (i.e. accessing `foo`). I'm trying to say `lp.foo = NULL;` to remove the reference to `lp`. – Sebastian Nov 30 '13 at 23:45
  • That doesn't make a difference. When resetting you effectively make a new shared_ptr and the old will get destroyed. Other people advised a null_deleter and that can help if passing a shared_ptr, but still you could end up in AV because the contained pointer is already out of scope. – gast128 Dec 01 '13 at 09:43
0

It seems this was a bad idea. A working, albeit more inconvenient solution is copying the object.

StructA lp;
lp.SomePreparation(...);
...
lp.SetSomething(...);
// my test
lp.foo.reset(new StructA());
lp.foo->var1 = lp.var1;
lp.foo->var2 = lp.var2; 


... more code
Sebastian
  • 1,408
  • 1
  • 20
  • 28