0

I have a class with two std::unique_ptr members. I want to set those members through the constructor.

Currently I'm doing this:

std::unique_ptr<Assignment> assignment{new Assignment{
       std::unique_ptr<Variable>{new Variable{"a"}},
       std::unique_ptr<Expression>{new Variable{"b"}}
}};

With regular pointers, I would just have done this:

auto assignment = new Assignment{new Variable{"a"}, new Variable{"b"}};
delete assignment;

Can I make the smart pointer version less verbose somehow? I was hoping something like this might work.

std::unique_ptr<Assignment> assignment{new Variable{"a"},{new Variable{"b"}};

However, the constructor of unique_ptr is explicit, so it doesn't.

bobbaluba
  • 3,584
  • 2
  • 31
  • 45
  • 4
    You could provide your own implementation of [`std::make_unique`](http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) to make some things a little easier. – Captain Obvlious Feb 18 '14 at 17:36
  • 3
    If you're looking for a way to implement `make_unique()`, I'd suggest: http://stackoverflow.com/questions/7038357/make-unique-and-perfect-forwarding. Also, note that in your second and third examples, you will leak memory if the construction of the second `new Variable` fails. (Which is part of the whole point of std::make_unique and std::make_shared). – Bill Lynch Feb 18 '14 at 17:38
  • @sharth: That could also be the case in the first example. I am not sure, but I believe the compiler can interleave the creation of the two `unique_ptr` arguments doing first the two `new` then the construction of the `unique_ptr`, potentially leaking memory. You need to interleave a function call (`make_unique`) to guarantee that no memory is leaked. – David Rodríguez - dribeas Feb 18 '14 at 17:52
  • @DavidRodríguez-dribeas: I believe you are correct. – Bill Lynch Feb 18 '14 at 17:54
  • 1
    @DavidRodríguez-dribeas If I read the standard correctly, no. In list initialization, the elements of the list are evaluated in order (possibly a first for C++), and the evaluation of each element is sequenced before the evaluation of the following. See 8.5.4/4. – James Kanze Feb 18 '14 at 18:16
  • Why do you have to allocate `Variable{"a"}` and `Variable{"b"}` on the heap? As I see it, you don't access them through a pointer to the base class so you can probably get rid of those two `new`s. If not, then please revise the question and add more details. – Ali Feb 18 '14 at 18:24
  • 1
    @JamesKanze: Thanks for the reference. I agree with your reading and now believe that it would be guaranteed not to leak. – David Rodríguez - dribeas Feb 18 '14 at 18:59
  • User of GCC should [beware that it still does not process braced-init-lists in the standard-mandated order](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253) in some circumstances. – Casey Feb 18 '14 at 19:38
  • btw most of the time you dont need up so try using values if possible – NoSenseEtAl Feb 19 '14 at 12:15
  • @NoSenseEtAl What's "up"? I'm using pointers because I want to use polymorphism. – bobbaluba Feb 19 '14 at 12:18
  • unique_ptr, and anyway for me it is rare to need 2 up of the same type but i guess you know what you are doing – NoSenseEtAl Feb 19 '14 at 12:20

2 Answers2

3

Is a perfect forwarding constructor an option?

// If you aren't using make_unique, you're doing it wrong.
template <typename T, typename...Args>
inline std::unique_ptr<T> make_unique(Args&&...args) {
    return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}

struct Variable {
    std::string name_;

    Variable(std::string name) : name_{std::move(name)} {}
};

struct Assignment {
    std::unique_ptr<Variable> a_, b_;

    template <typename T, typename U>
    Assignment(T&& a, U&& b) :
      a_{make_unique<Variable>(std::forward<T>(a))},
      b_{make_unique<Variable>(std::forward<U>(b))} {}
};

auto assignment = make_unique<Assignment>("a", "b");

Simplifies the syntax quite a bit, IMO.

Casey
  • 41,449
  • 7
  • 95
  • 125
0

The easiest solution would probably be

std::unique_ptr<Assignment> assignment {
   new Assignment{Variable{"a"}, Variable{"b"}}};

Of course, that requires a suitable Assignment(Variable&&, Variable&&) overload.

MSalters
  • 173,980
  • 10
  • 155
  • 350