Home > database >  Pass in unique pointer for inherited class to constructor with unique pointer for base class?
Pass in unique pointer for inherited class to constructor with unique pointer for base class?

Time:11-30

Is it possible to do the following: I have an inherited class B from base class A. I want to create a constructor for a method that takes in a unique pointer to class A but still accept unique pointers to class B, similar to pointer polymorphism.

void Validate(unique_ptr<A> obj) {obj->execute();}
...

unique_ptr<B> obj2;
Validate(obj2);

This doesn't seem to work as I've written it (I get a No matching constructor for initialization error), but I wonder if this is still possible?

CodePudding user response:

You cannot copy a unique pointer.

If you wish to transfer the ownership to the Validate function, then you must move from the unique pointer:

Validate(std::move(obj2));

A unique pointer parmeter accepted by Validate implies that it takes ownership, but that design sounds odd given the name of the function - but that may be due to missing context.

If ~A isn't virtual, then you may not use std::unique_ptr<A> because it would try to destroy the object through a pointer to the base which would result in undefined behaviour. You could use a custom deleter in such case.


If you don't wish to transfer ownership but instead the function should just access the object, then don't use a unique pointer parameter in the first place. Use a reference instead:

void Validate(A& obj) {
    obj.execute();
}

It doesn't matter whether the caller has a smart pointer or even whether the object is allocated dynamically.

You can use a bare pointer if you need to represent null, but if you don't need it (as is implied by your attempted implementation), then it's better to use reference since being able to avoid checking for null makes it easier to write a correct program.

CodePudding user response:

Your issue doesn't really have anything to do with polymorphism, but rather how unique_ptr<> works in general.

void Validate(unique_ptr<A> obj) means that the function will take ownership of the passed object. So, assuming that this is what the function is meant to do, you need to handoff said ownership as you call it.

In the code you posted, you would do this by moving the existing std::unique_ptr<>. This will ultimately (as in not the call to std::move() itself, but the handoff as a whole) null-out the original pointer. That's the whole point of unique_ptr<> after all: There can only be one of them pointing at a given object.

void Validate(unique_ptr<A> obj) {obj->execute();}

...

unique_ptr<B> obj2;
Validate(std::move(obj2));

// obj2 is now null.

By extension, if Validate() is not meant to take ownership of obj, then it should not accept a unique_ptr<> in the first place. Instead, it should accept either a reference or a raw pointer depending on whether nullptr is an expected valid value:

Ideally:

void Validate(A& obj) {
  obj.execute();
}

...

unique_ptr<B> obj2;
Validate(*obj2);

Alternatively:

void Validate(A* obj) {
  if(obj) {
    obj->execute();
  }
}

...

unique_ptr<B> obj2;
Validate(obj2.get());
  •  Tags:  
  • c
  • Related