76

I have a C++ object of type ObjectArray

typedef map<int64_t, std::unique_ptr<Class1>> ObjectArray;

What is the syntax to create a unique_ptr to a new object of type Class1 and insert it into an object of type ObjectArray?

vigs1990
  • 1,639
  • 4
  • 17
  • 19
  • The following MSDN page has some info on this: http://msdn.microsoft.com/en-us/library/vstudio/hh279676.aspx – yuyang Jun 04 '13 at 17:19
  • https://stackoverflow.com/questions/26446352/what-is-the-difference-between-unordered-mapemplace-and-unordered-mapinsert – Dmitriy Volkov Oct 21 '21 at 11:52

3 Answers3

92

As a first remark, I wouldn't call it ObjectArray if it is a map and not an array.

Anyway, you can insert objects this way:

ObjectArray myMap;
myMap.insert(std::make_pair(0, std::unique_ptr<Class1>(new Class1())));

Or this way:

ObjectArray myMap;
myMap[0] = std::unique_ptr<Class1>(new Class1());

The difference between the two forms is that the former will fail if the key 0 is already present in the map, while the second one will overwrite its value with the new one.

In C++14, you may want to use std::make_unique() instead of constructing the unique_ptr from a new expression. For instance:

myMap[0] = std::make_unique<Class1>();
Jo Liss
  • 30,333
  • 19
  • 121
  • 170
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 2
    Another option is the emplace member: myMap.emplace (0, new Class1). Not all libraries support this member, yet, though. – Nathan Ernst Jun 04 '13 at 23:37
  • @milleniumbug I'm pretty sure that's not legal C++. The problem is that the rvalue reference overload of `insert` is a function template, but the braced initializer doesn't give enough information to deduce the template argument. – Geoff Romer Dec 19 '13 at 17:49
  • @GeoffRomer: There is an overload of `insert` that takes a `const value_type& value` (the first overload in [this list](http://en.cppreference.com/w/cpp/container/map/insert)). – Andy Prowl Dec 19 '13 at 18:19
  • 1
    @AndyProwl I know, but that overload requires value_type to be copyable, and in this case it isn't. – Geoff Romer Dec 19 '13 at 22:57
  • @GeoffRomer: Oh, you're right! I got distracted somehow, good catch. Will edit the answer :) – Andy Prowl Dec 20 '13 at 09:49
  • Doesn't myMap[0] = std::unique_ptr(new Class1()); invokes the copy constructor? std::unique_ptr doesn't have one for obvious reasons (pointer is "unique"). Did you compile this?. As @NathanErnst said use emplace. – wgodoy Oct 27 '16 at 19:45
  • 1
    @wgodoy, if you're referring to the copy constructor of the unique_ptr, no, it would invoke the move assignment operator. – Nathan Ernst Oct 28 '16 at 21:40
74

If you want to add an existing pointer to insert into the map, you will have to use std::move.

For example:

std::unique_ptr<Class1> classPtr(new Class1);

myMap.insert(std::make_pair(0,std::move(classPtr)));

or similar:

myMap[0] = std::move(classPtr);

if one wants insert a new or overwrite an already resisting key.

ead
  • 32,758
  • 6
  • 90
  • 153
Saurabh
  • 787
  • 5
  • 4
  • 5
    Also: myMap.insert({0, std::move(classPtr)}); should work; – korst1k Oct 31 '18 at 08:00
  • thank you for pointing this out.. I was struggling to push an existing pointer to a map and was at the verge of dropping out and just scrolled down to see your answer.. relieved! – Vivek Jan 17 '19 at 14:11
  • and if you want to get the value from the map, std::unique_ptr c1 = std::move(myMap[0]);? – Rony Tesler Jan 29 '23 at 14:17
7

In addition to previous answers, I wanted to point out that there is also a method emplace (it's convenient when you cannot/don't want to make a copy), so you can write it like this:

ObjectArray object_array;
auto pointer = std::make_unique<Class1>(...);  // since C++14
object_array.emplace(239LL, std::move(pointer));
// You can also inline unique pointer:
object_array.emplace(30LL, std::make_unique<Class1>(...));
antonpp
  • 2,333
  • 23
  • 28