0

I would like to use unique_ptr inside map in vector. But I got an error message. I am not sure why and how to solve this problem.
This is the code.

#include <memory>

int main(int argc, char** argv)
{
    std::vector<std::map<int, std::unique_ptr<std::string>>> outputContainers;
    std::map<int, std::unique_ptr<std::string>> outputContainer;
    outputContainer[0] = std::make_unique<std::string>("test");
    outputContainers.push_back(std::move(outputContainer));
}

This is an error message.

Error C2280 'std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>>::pair(const std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>> &)': attempting to reference a deleted function test C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.24.28314\include\xmemory  671 
Masahiro
  • 155
  • 9
  • 1
    [It works for me](https://godbolt.org/z/xWL_s8 "Compiler Explorer link"), as long as I add the other necessary headers. – Daniel H Feb 13 '20 at 06:20
  • @DanielH Could you tell me which order did you install which library and which version of visual studio do you use? – Masahiro Feb 13 '20 at 06:26
  • @DanielH There is difference between G++ and CL.EXE compiler from visual. – rafix07 Feb 13 '20 at 06:28
  • @rafix07 Yeah, I see that when I switch to the latest MSVC compiler there, it fails. It looks like it’s trying to call a copy constructor instead of a move constructor? I think that’s an issue with MSVC and the standard says it should work, not that this actually helps much. – Daniel H Feb 13 '20 at 06:35
  • @rafix07 With VS2015, it works fine for me. Which version you have problems with? – TonySalimi Feb 13 '20 at 12:43
  • @Gupta I am using VS2019. If I use G++, it works fine. – Masahiro Feb 15 '20 at 09:36
  • Even just `std::vector>> outputContainers; outputContainers.resize(1);` already fails. Somehow, the vector chooses to copy, and not to move, elements when resizing. I seem to remember that something needs to be `noexcept` to allow the vector to move on reallocation. – Igor Tandetnik Feb 15 '20 at 15:33

1 Answers1

1

When a vector needs to reallocate, it may move elements to the new storage if the element's type is_nothrow_move_constructible; otherwise, it has to copy (so it can unwind back to the original state if any constructor throws an exception).

std::map's move constructor is not required to be noexcept. Some implementations may provide stronger guarantees than required by the standard, and make it noexcept; others may not.

The interaction of these two facts leads to a vector of maps of move-only type being non-portable - it may compile with some implementations but not others.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85