14

Consider the following line of code:

auto source1 = std::unique_ptr<IGpsSource>(new GpsDevice(comPort, baudrate));
auto source2 = std::unique_ptr<IGpsSource>(new GpsLog(filename));

How can that be written using the new std::make_unique function, supported by VS 2013? Is it even possible?*

*My problem is that I don't know how to tell std::make_unique what kind of object to instantiate. Because only the constructor's parameters are passed in there seems to be no control over that.

ilya1725
  • 3,506
  • 6
  • 31
  • 53
Boris
  • 7,424
  • 21
  • 59
  • 105

2 Answers2

17

Yes, you can of course use make_unique for that, but it's not as useful as you might want. You have these options:

std::unique_ptr<IGpsSource> source1 = std::make_unique<GpsDevice>(comPort, baudrate);
auto source2 = std::unique_ptr<IGpsSource>{ std::make_unique<GpsLog>(filename) };

I would say the real question is "why do you want that?"

  1. Unlike make_shared, make_unique has no allocation benefits over new. So if you need control of the pointer's type, what you're doing is just fine.

  2. Why do you need the pointer to be typed to IGpsSource in the first place? An implicit conversion from std::unique_ptr<Derived> rvalues to std::unique_ptr<Base> rvalues exists. So if you're actually calling make_unique to initialise an IGpsSource pointer, it will work just fine. And if you want to transfer the pointer somewhere, you'll have to std::move it anyway, at which point the conversion can happen again.

Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
  • 8
    Exception safety argument [from this answer](http://stackoverflow.com/a/20895705/673852) still applies to `make_unique`, not only to `make_shared`. So, `make_unique()` should be preferred over `unique_ptr(new Xyz)`. – Ruslan Dec 20 '16 at 14:54
  • @Ruslan Note that the exception safety criterion applies to multiple allocations being done in a single expression. The OP's case is quite different: they have only a single allocation, and want precise control over the pointer's type. – Angew is no longer proud of SO Dec 20 '16 at 19:59
  • @ajmal-kunnummai's [answer](https://stackoverflow.com/a/49619801/754300) makes more succinct use of `std::make_unique()`. – Kevin Nov 10 '18 at 02:44
17
std::unique_ptr<Base> base_ptr = std::make_unique<Derived>();

As Angew said, the above should work fine. Provided Derived uses public inheritance. Just wanted to add that for completeness.

Ajmal Kunnummal
  • 711
  • 7
  • 7