1

I have a class that contains a unique_ptr. I want to place instances of this class inside a container (specifically std::map). This works using std::move and .emplace however, I would like to perform all this initialization within the container's initializer list. Is this possible?

I suspect Foo gets initialized in the initializer list then copied which is causing the problem. I've tried added a std::move in the initializer list but that hasn't solved the problem.

class Foo
{
public:
  std::unique_ptr<std::string> my_str_ptrs;
}

Compilation Fails "attempting to access a deleted function". This is an example of what I want to do

std::map<std::string, Foo> my_map{
  {"a", Foo{}}
};

Compilation Succeeds

std::map<std::string, Foo> my_map;
my_map.emplace("a", Foo{});
J'e
  • 3,014
  • 4
  • 31
  • 55
  • Change `std::unique_ptr my_str_ptrs;` to `std::vector my_strs` – NathanOliver Sep 27 '21 at 12:56
  • What about writing a copy-constructor for `class Foo`, which will perform the copy from `Foo{}` in the way, you intend. For `std::unique_ptr` you can use cloning to perform the copy properly. – Karen Baghdasaryan Sep 27 '21 at 13:32
  • @KarenBaghdasaryan, I tried this but got the same results. Based on the answer from kaldrr , unless I change the std::initializer_list code, I don't think there is any way to make this work. – J'e Sep 27 '21 at 14:13
  • @J'e I thought that as far as it will be bound to const lvalue ref, it would be possible to clone the content of `my_str_ptrs` and the the copied variable should have a `std::unique_ptr` to it. – Karen Baghdasaryan Sep 27 '21 at 14:20

1 Answers1

3

It's fault of std::initializer_list, if you look at it's begin/end member functions, they return const T*, which means it will force std::map to try use the copy constructor of your Foo, which is deleted as std::unique_ptr can not be copied.

This issue is not unique to std::map, any container which allows you to initialize it with std::initializer_list will really copy the arguments from an initializer list.

The C++ standard requires that during such initialization there's a temporary const T[N] array, which the std::initializer_list points to, const disables moves from it.

Kaldrr
  • 2,780
  • 8
  • 11