10

I need to create a std::unique_ptr from a class that has a constructor that takes one parameter. I can´t find references on how to do it. Here is the code example that cannot compile:

#include <iostream>
#include <string>
#include <sstream>
#include <memory>

class MyClass {

    public:
        MyClass(std::string name);
        virtual ~MyClass();

    private: 
        std::string myName;
};

MyClass::MyClass(std::string name) : myName(name) {}
MyClass::~MyClass() {}

class OtherClass {

    public:
        OtherClass();
        virtual ~OtherClass();

        void MyFunction(std::string data);

        std::unique_ptr<MyClass> theClassPtr;
};

OtherClass::OtherClass() {}
OtherClass::~OtherClass() {}

void OtherClass::MyFunction(std::string data)
{
    std::unique_ptr<MyClass> test(data); <---------- PROBLEM HERE!
    theClassPtr = std::move(test);
}

int main()
{
    OtherClass test;
    test.MyFunction("This is a test");
}

The errors are related to the way I´m initializing the std::unique_ptr, pointed out in my code.

The original code and the errors can be found here.

Thanks for helping me to solve that.

Mendes
  • 17,489
  • 35
  • 150
  • 263
  • Use `std::make_unique`, which forwards its arguments to the constructor. – David Schwartz Jul 01 '15 at 23:31
  • I tried, but I can´t make it compile... seens that std::make_unique is not supported on C++11.... – Mendes Jul 01 '15 at 23:33
  • Can you show the code that didn't work? – David Schwartz Jul 01 '15 at 23:35
  • 'std::unique_ptr temp = std::make_unique(data); theClassPtr = std::move(temp);' – Mendes Jul 01 '15 at 23:38
  • Check the error here http://coliru.stacked-crooked.com/a/fb3148d5886ba29e – Mendes Jul 01 '15 at 23:40
  • Wow, I'm so used to working on projects that have this fixed I forgot that a workaround was needed! – David Schwartz Jul 01 '15 at 23:50
  • Something that I noticed with your code that would help but doesn't address your current question. In your first class's constructor it is only taking 1 argument - I would use the explicit keyword before the Constructor's name in its declaration. Also in both of your classes there is no need to have your destructors as virtual since you are not using inheritance. If you only need the default destructors then you can omit them altogether. – Francis Cugler Jul 02 '15 at 03:15

4 Answers4

11

You can do:

std::unique_ptr<MyClass> test(new MyClass(data));

Or if you have C++14

auto test = std::make_unique<MyClass>(data);

But:

In the provided example there is no need to create a temporary variable, you can just use the reset method of the class member:

theClassPtr.reset(new MyClass(data));
Galik
  • 47,303
  • 4
  • 80
  • 117
  • Or, you could simply eliminate the `test` variable and just use `theClassPtr.reset(new MyClass(data));` instead. – Remy Lebeau Jul 02 '15 at 00:06
  • @RemyLebeau Thank you, I lost sight of the original problem, thanks for pointing that out. Now fixed. – Galik Jul 02 '15 at 00:17
1
#include <memory>
...

int main()
{
    std::string testString{ "Testing 1...2....3" };
    auto test = std::make_unique<MyClass>( testString );
    return 0;
}
davepmiller
  • 2,620
  • 3
  • 33
  • 61
1

It's basically an oversight. You need this:

#include <memory>

namespace std
{

    template <class T, class... Args>
    std::unique_ptr <T> make_unique (Args&&... args)
    {
        return std::unique_ptr <T> (new T (std::forward <Args> (args)...));
    }
}
David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Adding functions to std is illegal. Put it in `notstd`. – Yakk - Adam Nevraumont Jul 02 '15 at 00:01
  • If it's illegal, then every C++ standard is illegal. – David Schwartz Jul 02 '15 at 00:04
  • @DavidSchwartz: perhaps you meant "every C++ standard *library implementation* is illegal"? – Remy Lebeau Jul 02 '15 at 00:11
  • How the functions get in `std` is undefined. Bit it is clearly illegal for a C++ program to add functions to the `std` namespace (other than via those `#include` directives). Yes, it is likely to work, but so was accessing 3 ints in a row on the stack by pointer arithmetic at one point. Don't ignore the standard and venture into ill formed programs when there isn't a good reason. – Yakk - Adam Nevraumont Jul 02 '15 at 00:24
  • @Yakk There is a good reason -- to be able to write programs today that are ready for C++14. This is way better than having to fix the code everywhere, a lesson painfully learned by not doing this for C++11. – David Schwartz Jul 02 '15 at 13:52
  • 1
    @david odr, standard changes, bugs in your implementation or your std library, incoming modules are all possible issues. Plus your code is explicitly banned in the standard as making your program ill formed. The cost of using `notstd` or similar is deleting 3 characters, or if that is too much work adding `using std::make_unique` to `notstd`. Your reason is meh, not good: on the other hand, "fastest possible delegates" is an example of a good reason to write an ill formed program. – Yakk - Adam Nevraumont Jul 02 '15 at 17:49
0

C++14 comes with std::make_unique. It was omitted from C++11.

Writing it yourself is easy:

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

now use it like this:

auto foo = notstd::make_unique<MyClass>(string);

will make your unique ptr for you.

This pattern has a few advantages. First, it removes a new that is not paired with a delete from "user code", which makes me happy.

Second, if you call a function that takes 2 unque ptrs, ths above can avoid leaks in case of exceptions being thrown.

We put this in notstd as injecting new functions into std is illegal inder the standard (no diagnostic required).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524