8

This simple code cannot be compiled in Visual Studio 2019 (latest update).

#include <vector>
#include <map>
#include <memory>

int main()
{
    std::vector<std::map<int, std::unique_ptr<int>>> v;
    v.resize(1);
}

The error is:

Severity    Code    Description Project File    Line    Suppression State
Error   C2280   'std::pair<const int,std::unique_ptr<int,std::default_delete<int>>>::pair(const std::pair<const int,std::unique_ptr<int,std::default_delete<int>>> &)': attempting to reference a deleted function  Test    C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.26.28801\include\xmemory  671 

emplace_back() is also not working. Visual Studio 2015 and the latest gcc does not have a problem with it. Is the code wrong or the compiler? What can I do to make it compile?

kiba
  • 91
  • 2
  • Please update subject with "... not usable in VS", otherwise it is quite confusing. – Slava Jun 30 '20 at 13:28
  • 5
    Related: https://stackoverflow.com/q/53527682/6865932 – anastaciu Jun 30 '20 at 13:31
  • 3
    Quick answer: in Microsoft's implementation, move constructor of `std::map` is _not_ `noexcept`, therefore, `std::vector` will prefer its copy constructor in `resize`. And, this copy constructor cannot be used because of `std::unique_ptr` element type. – Daniel Langr Jun 30 '20 at 13:39
  • 2
    It's also worth noting that it doesn't appear that [`std::map` is required to have a `noexcept` copy constructor](https://en.cppreference.com/w/cpp/container/map/map). E.g. the MSVC implementation is compliant and the code is not portable as it relies on *implementation defined* extension. – Mgetz Jun 30 '20 at 13:41
  • @Mgetz Copy constructors of containers generally cannot be noexcept, since they need to allocate. But noexcept specification for copy constructors isn't related to OP's problem, its noexcept specification of move constructor what matters here. And yes, `std::map` is not required to have noexcept move constructor. – Daniel Langr Jun 30 '20 at 13:43
  • @DanielLangr I'm aware, but the move isn't marked as `noexcept` either. I'm actually curious how libstdc++ did this and if it's compliant with the standard. – Mgetz Jun 30 '20 at 13:44
  • @Mgetz Yes, an implementation [is allowed to strengthen `noexcept` specification](http://eel.is/c++draft/library#res.on.exception.handling-5). – Daniel Langr Jun 30 '20 at 13:45
  • 1
    so are you all telling me that the construct vector> is no portable c++ anymore? that seems not to be very thought out, to stay polite. – kiba Jun 30 '20 at 13:46
  • @DanielLangr I'm well aware, just curious *how* they pulled it off – Mgetz Jun 30 '20 at 13:46
  • @kiba it was never portable. The standard doesn't require `noexcept` copy on maps due to the allocation. libstdc++ has extended the library as they are allowed and provided the functionality. But it's not guaranteed to be there on other platforms or implementations. – Mgetz Jun 30 '20 at 13:47
  • As a workaround, you can create a vector of (unique) pointers to maps containing unique pointers (or any not-noexcept move constructible types). Move constructor of a unique pointer is required to be `noexcept`. – Daniel Langr Jun 30 '20 at 13:58
  • 2
    What anastaciu found is a duplicate: [Deleted Function in std::pair when using a unique\_ptr inside a map](https://stackoverflow.com/questions/53527682/deleted-function-in-stdpair-when-using-a-unique-ptr-inside-a-map) – Davis Herring Jun 30 '20 at 15:01
  • @DavisHerring I didn't want to close it, it's an interesting question, but you're right it's very similar. – anastaciu Jun 30 '20 at 22:14
  • I think it is dangerous to have such a type because it is not portable c++ and therefore not very usable. Compilers should at least warn about this. Thanks for answering the question so far, maybe someone can summerize everything in an answer. – kiba Jul 01 '20 at 08:23

0 Answers0