0

I have question. Let's have this code:

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

class Writable {
public:
    virtual ~Writable() = default;
    virtual void write(std::ostream& out) const = 0;
};

class String : public Writable {
public:
    String(const std::string& str) : m_str(str) {}
    virtual ~String() override = default;
    virtual void write(std::ostream& out) const override { out << m_str << '\n'; }
private:
    std::string m_str;
};

class Number : public Writable {
public:
    Number(double num) : m_num(num) {}
    virtual ~Number() override = default;
    virtual void write(std::ostream& out) const override { out << m_num << '\n'; }
private:
    double m_num;
};

int main() {
    std::unique_ptr<Writable> str1(new String("abc"));
    std::unique_ptr<Writable> num1(new Number(456));

    str1->write(std::cout);
    num1->write(std::cout);
}

I dont understand why unique_pointers are defined like this:

std::unique_ptr<Writable> str1(new String("abc"));

Its some kind of shorthand? Or I must do it this way? Is there some kind of equivalent? For example like:

std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Baterka
  • 3,075
  • 5
  • 31
  • 60

3 Answers3

6

Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator.

std::unique_ptr<Writable> str1(new String("abc"));

Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator and move constructing another unique_ptr with it.

std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));

However compiler can (most likely) perform move elison and make the above two equivalent.

The right way to initialize from c++14 and later is below

std::unique_ptr<Writable> v1 = std::make_unique<String>();
balki
  • 26,394
  • 30
  • 105
  • 151
1

The form of initialization in

std::unique_ptr<Writable> str1(new String("abc"));

is called direct initialization. If the constructor is marked explicit (like in explicit unique_ptr(pointer p) noexcept constructor), this form of initialization is required.

explicit constructor disables copy initialization in the form of std::unique_ptr<Writable> str1 = new String("abc");.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
0

Just like you can write

std::vector<int> foo(10);

to create a vector of 10 int's

std::unique_ptr<Writable> str1(new String("abc"))

creates a std::unique_ptr<Writable> that points to a new String("abc"). It is the same as doing

std::vector<int> foo = std::vector(10);

and

std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));

except that the later cases use copy initialization which can be different in some cases.


To save on some typing you could use

auto str1 = std::make_unique<String>("abc");

instead when you declare your unique_ptr's

NathanOliver
  • 171,901
  • 28
  • 288
  • 402