Question

This is with XCode C++ language dialect c++1y. Help me understand unique_ptr:

//1

    auto ouput2 = make_unique<standard::Algorithm>(AlgorithmFactory::create("YamlOutput",
                                                                               "filename", outputFilename));

//2

    unique_ptr<standard::Algorithm> output(standard::AlgorithmFactory::create("YamlOutput",
                                                                                  "filename", outputFilename));

1 fails with build with "Semantic Issue: Allocating an object of abstract class type 'essentia::standard::Algorithm", but 2 succeeds.

I read that these two are equivalent, so how come one succeeds and the other doesn't?

I look at the source for AlgorithmFactory::create() it returns a BaseAlgorithm* depending on the string input. Not really understanding the object hierarchy since standard::Algorithm doesn't seem to have anything to do with BaseAlgorithm (it doesn't extend it).

This is how the documentation for the Essentia library I am using did it except they were using a naked pointer.

Was it helpful?

Solution 2

The two statements aren't equivalent. The difference is:

  • Your second version is calling the unique_ptr constructor by providing an existing raw pointer to the object. It only encapsulates that object pointer in a unique_ptr.

  • The first version is supposed to be provided with the constructor arguments for your object, and it will create the object for you in a safe way. It both constructs and encapsulates an object in a unique_ptr.

The problem is that your factory already allocates the object and returns a raw pointer to it. At that point it doesn't make sense anymore to use make_unique since the purpose of that function is to avoid dealing with raw pointers completely, i.e. construct-and-wrap in one go.

You have two options here:

  1. Stick to your second version.

  2. Change the factory such that it returns a unique_ptr by using make_unique in its implementation. But it could make sense to also provide a shared_ptr-version of the same factory. Something like createUnique + createShared, and maybe keep the existing create which returns a raw pointer. That's a question of code style however.

OTHER TIPS

They aren't equivalent. make_unique creates the object whereas unique_ptr simply wraps an existing pointer.

Your first line is equivalent to unique_ptr<standard::Algorithm>(new standard::Algorithm(AlgorithmFactory::create(...))). Note the usage of new here.

std::make_unique<T> forwards its arguments to T's constructor and constructs a new T, then makes a std::unique_ptr<T> that points to the newly constructed T. If T is an abstract class then this will definitely fail. Even if T were not an abstract class, this would likely not compile since the AlgorithmFactory::create function presumably returns a T*. On the other hand, std::unique_ptr<T>'s constructor takes an argument convertible to T*, and there is no problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top