How to Implement Make_Unique Function in C++11

How to implement make_unique function in C++11?

Copied from make_unique and perfect forwarding (the same is given in Herb Sutter's blog)

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

If you need it in VC2012, see Is there a way to write make_unique() in VS2012?


Nevertheless, if the solution in sasha.sochka's answer compiles with your compiler, I would go with that one. That is more elaborate and works with arrays as well.

Why does C++11 have `make_shared` but not `make_unique`

According to Herb Sutter in this article it was "partly an oversight". The article contains a nice implementation, and makes a strong case for using it:

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

Update: The original update has been updated and the emphasis has changed.

Why I cannot pass std::make_unique S as a function parameter?

The signature for std::make_unique is

template<class T, class... Args>
unique_ptr<T> make_unique(Args&& ...args);

If you call make_unique directly the compiler is using template argument deduction to deduce what Args should be from what you are invoking it with. By passing std::make_unique<S> to your function, you are stating that Args is an empty parameter pack, and therefore std::make_unique is expecting zero parameters and tries to default construct an S. It is the same as calling std::make_unique<S>(); directly.

Extending namespace std to implement make_unique when using C++11

No, this is forbidden—even though, via

#define make_unique ? ? ?

a conforming C++11 program can be quite sure that the library never mentions the name (outside of a stringization) and would thus be unable to detect the extension.

How to create a wrapper for `std::make_unique T `?

You need to forward properly the values, and you need to expand the pack.

First, make it compile:

template<typename T, typename... Args>
UniquePtr<T> MakeUnique(Args... args) // not recursive
{ // ^---- no need for <T> when defining function template
return std::make_unique<T>(args...); // the ... expands the pack
}

Then, you need to forward, because args... will copy everything. You want to move rvalues, and copy lvalues:

template<typename T, typename... Args>
UniquePtr<T> MakeUnique(Args&&... args)
{
return std::make_unique<T>(std::forward<Args>(args)...);
}

Can std::make_unique take the output of a function as an argument?

Is there a way to use make_unique and pass the output of a function as a parameter?

std::make_unique<T> takes constructor arguments to create a new T. It does not take a T* to an existing T.

Furthermore, you can't specify a deleter with it like that.

You mean simply:

std::unique_ptr<SDL_Surface, SurfaceDeleter> loadedSurface3{IMG_Load(path.c_str())};

is loadedSurface2 recommended over loadedSurface1 because it uses make_unique?

I can't see any benefit there. All you've achieved is to split your construction over two lines and lose the deleter.

make_unique and perfect forwarding

Herb Sutter, chair of the C++ standardization committee, writes on his blog:

That C++11 doesn’t include make_unique is partly an oversight, and it will almost certainly be added in the future.

He also gives an implementation that is identical with the one given by the OP.

Edit: std::make_unique now is part of C++14.

C++ use of deleted function with unique_ptr, make_unique

In general, most of your errors originate from that std::unique_ptr has no copy constructor. This is so that it can efficiently manage the scope of the pointer inside of it. One way around this is to create a new std::unique_ptr, and copy all individual values over.

I've written an example class for you, perhaps it can help.

#include <memory>

template <class T>
class Matrix
{
private:
std::unique_ptr<T[]> data = nullptr;
size_t height, width;
public:
Matrix(size_t h, size_t w)
: height(h), width(w)
{
if(h*w == 0) return;
data = std::make_unique<T[]>(h*w);
}

Matrix(const Matrix& other)
{
height = other.height;
width = other.width;

data = std::make_unique<T[]>(height * width);

for(size_t i = 0; i < height; i++)
{
for(size_t j = 0; j < width; j++)
{
(*this)(j, i) = other(j,i);
}
}
}

Matrix operator=( const Matrix& other )
{
if(this == &other)
{
return *this;
}

height = other.height;
width = other.width;

data.reset(std::make_unique<T[]>(other.height * other.width));

for(size_t i = 0; i < height; i++)
{
for(size_t j = 0; j < width; j++)
{
(*this)(j, i) = other(j,i);
}
}

return *this;
}

T & operator()(size_t x, size_t y)
{
//If data is nullptr then this is undefined behaviour.
//Consider adding a throw or assert here
return data[y * height + x];
}

T operator()(size_t x, size_t y) const
{
//If data is nullptr then this is undefined behaviour.
//Consider adding a throw or assert here
return data[y * height + x];
}

size_t getHeight() const
{
return height;
}

size_t getWidth() const
{
return width;
}
};

As a final statement, if what you want to do is to create matrices for mathematical purposes, I suggest you give them static sizes for performance reasons. Adding in mathematical operators to a class like this involves additional logic for the cases where dimensions are mismatched. Statically sized matrices will solve this by themselves due to their typing. You can still do it like this, but be wary of any edge cases.



Related Topics



Leave a reply



Submit