jeudi 25 août 2016

c++ shared_ptr copy construction with custom deleter via placement new

Going off of this question, trying to clarify if what follows is a safe / legitimate idiom to use.

In short, I have a discriminated union eg

struct var {
  union {
    char uchar;
    shared_ptr< void > uptr;
  };
};

And at some point I will need to construct uptr in-place. My current code to construct it in-place in a copy operation (so that the reference count goes up by one, still referring to the same object as another shared_ptr) looks like this:

void var::copy (const var & v) {
  *(new ( &uptr ) decltype ( uptr )) = v.uptr;
}

The reason for this seemingly odd approach is I do need the deleter to be transferred as well. In my situation I could create another instance of the deleter since this union/variant type is a tagged sort but that seems inelegant if shared_ptr is already up to the task.

I know for a fact from that question linked, that operator= will copy the deleter. However will a copy-constructed shared_ptr also copy the deleter? I assume it would, so in that case this should work, but will it maintain the same deleter for the new copy?

void var::copy (const var & v) {
  new ( &uptr ) decltype ( uptr ) (v.uptr);
}

First, I realize it's trivial to ask "does the copy constructor work the same as copy-assignment" but I want to be sure of this or if there are any caveats to be mindful of (the header files are a bit 'thick' to read as-is, reference material isn't very clear on this, I can't tell for sure in short).

Furthermore unique_ptr explicitly has a deleter type as a template parameter to the class itself while shared_ptr does not, and again I know in theory why this is but not sure of what actually happens inside shared_ptr and how it behaves in these situations.

Second, of the two forms assuming they both work the same way, or another if it's cleaner than either of these, which is preferred? Which is safer?

Note - the above code is not complete of course, only the relevant / functional lines are shown as the rest is tagged-union related (large condition blocks), and other union fields are not shown for brevity.

Aucun commentaire:

Enregistrer un commentaire