6

Suppose I have the need to do the following (This is just some imaginative code for discussion of the C++ standard, thus I won't discuss why I design it this way, so don't bother me with something like: your design is wrong.)

T* ptr = new T;
shared_ptr<T> p(ptr);
shared_ptr<T> q(ptr, SomeDeleterThatDoesnotDeleteButDoSomeOtherStuff());

Suppose the logic guarantees that p or some of its copies lives longer than all copies of q, so practically there won't be any problem. My question is, is it forbidden by C++ standard, e.g. explicitly stated as UB by C++ standard, for different shared_ptr counters to share the same address?

Thanks.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Kan Li
  • 8,557
  • 8
  • 53
  • 93
  • 1
    What if you `return q;`? – Peter Wood Jun 18 '12 at 09:14
  • @Peter I think that's the idea — to invoke the non-deleter and do something useful with the knowledge that some subset of references is now empty. – Potatoswatter Jun 19 '12 at 04:29
  • The design isn't *that* terrible for its purpose. You could guarantee proper destruction by replacing the custom deleter with one that *does* delete, and also owns its own `shared_ptr` 1. to a dummy object that performs the action in its destructor or 2. having another custom deleter that performs the action. But those methods could be less efficient, if the set(s) of `q` objects changes rapidly relative to the set of proper owners `p`. – Potatoswatter Jun 19 '12 at 04:39
  • @Potatoswatter, you got it. This is actually exactly what I did in my actual work: let the non-deleter owns the `p`. – Kan Li Jun 19 '12 at 05:24
  • @icando But... when `p` goes out of scope it will delete `ptr`, and the returned `q` will point to an invalid object, with no way of knowing. This seems like a really bad idea. What are you trying to achieve? – Peter Wood Jun 19 '12 at 07:35
  • @PeterWood, please read my questions, please. I've already said logic guarantees `p` or some of its copies lives longer than all copies of `q`. I've also said I am not welcome on the criticism of the design itself. In previous comments I've already said letting `q`'s deleter hold a copy of `p` can achieve this guarantee, which is the implementation detail I thought not interesting to talk about so didn't put in the question. Therefore the situation you insisted in your comment will never happen. – Kan Li Jun 20 '12 at 18:24

2 Answers2

5

If the first shared_ptr object is destroyed, then you get UB because objects using the second might access released object.

Since you made sure that your first shared_ptr object lives longer then the second, you do not get UB.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
2

I can't find anything in the standard (well, the final draft) that specifically rules it out. The closest I can find is a note in 20.9.11.2.10 shared_ptr casts

5 [ Note: The seemingly equivalent expression shared_ptr(static_cast(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. —end note ]

which actually seems to forget about your case with a custom deleter.

BoBTFish
  • 19,167
  • 3
  • 49
  • 76