I have a vector of map. The maps contain a struct that is move-only.
When I try to interact with this structure, I get compilation errors on MSVC.
Here's a sample code:
#include <map>
#include <memory>
#include <vector>
struct S {
std::unique_ptr<int> a;
};
int main() {
std::vector<std::map<float, S>> s;
s.emplace_back();
return 0;
}
I get an error on the s.emplace_back()
line:
C:/data/msvc/14.28.29333/include\xmemory(701): error C2280: 'std::pair<const float,S>::pair(const std::pair<const float,S> &)': attempting to reference a deleted function
C:/data/msvc/14.28.29333/include\utility(209): note: see declaration of 'std::pair<const float,S>::pair'
C:/data/msvc/14.28.29333/include\utility(209): note: 'std::pair<const float,S>::pair(const std::pair<const float,S> &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'S::S(const S &)'
<source>(7): note: 'S::S(const S &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)'
C:/data/msvc/14.28.29333/include\memory(2686): note: 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': function was explicitly deleted
C:/data/msvc/14.28.29333/include\xtree(358): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,_Ty&>(_Alloc &,_Objty *const ,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<std::allocator<std::pair<const float,S>>>::void_pointer>>,
_Ty=std::pair<const float,S>,
_Objty=std::pair<const float,S>
]
C:/data/msvc/14.28.29333/include\xtree(358): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,_Ty&>(_Alloc &,_Objty *const ,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<std::allocator<std::pair<const float,S>>>::void_pointer>>,
_Ty=std::pair<const float,S>,
_Objty=std::pair<const float,S>
]
C:/data/msvc/14.28.29333/include\xtree(2027): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>::_Buynode<std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>>,_Ty&>(std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>> &,std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Ty=std::pair<const float,S>
]
C:/data/msvc/14.28.29333/include\xtree(2027): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>::_Buynode<std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>>,_Ty&>(std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>> &,std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Ty=std::pair<const float,S>
]
C:/data/msvc/14.28.29333/include\xtree(1741): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Buynode<std::pair<const float,S>&>(std::pair<const float,S> &)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>
]
C:/data/msvc/14.28.29333/include\xtree(1741): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Buynode<std::pair<const float,S>&>(std::pair<const float,S> &)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>
]
C:/data/msvc/14.28.29333/include\xtree(1762): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_or_move<std::pair<const float,S>,std::integral_constant<bool,false>>(std::pair<const float,S> &,std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_tag,_Is_set)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Is_set=std::integral_constant<bool,false>
]
C:/data/msvc/14.28.29333/include\xtree(1762): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_or_move<std::pair<const float,S>,std::integral_constant<bool,false>>(std::pair<const float,S> &,std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_tag,_Is_set)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Is_set=std::integral_constant<bool,false>
]
C:/data/msvc/14.28.29333/include\xtree(1728): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_nodes<_Moveit>(std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,_Moveit)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Moveit=std::_Tree<std::_Tmap_traits<float,S,std::less<float>,std::allocator<std::pair<const float,S>>,false>>::_Copy_tag
]
C:/data/msvc/14.28.29333/include\xtree(1728): note: see reference to function template instantiation 'std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_nodes<_Moveit>(std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer> *,_Moveit)' being compiled
with
[
_Alloc=std::allocator<std::pair<const float,S>>,
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Moveit=std::_Tree<std::_Tmap_traits<float,S,std::less<float>,std::allocator<std::pair<const float,S>>,false>>::_Copy_tag
]
C:/data/msvc/14.28.29333/include\xtree(902): note: see reference to function template instantiation 'void std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy<std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_tag>(const std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>> &,_Moveit)' being compiled
with
[
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Alloc=std::allocator<std::pair<const float,S>>,
_Moveit=std::_Tree<std::_Tmap_traits<float,S,std::less<float>,std::allocator<std::pair<const float,S>>,false>>::_Copy_tag
]
C:/data/msvc/14.28.29333/include\xtree(902): note: see reference to function template instantiation 'void std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy<std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Copy_tag>(const std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>> &,_Moveit)' being compiled
with
[
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Alloc=std::allocator<std::pair<const float,S>>,
_Moveit=std::_Tree<std::_Tmap_traits<float,S,std::less<float>,std::allocator<std::pair<const float,S>>,false>>::_Copy_tag
]
C:/data/msvc/14.28.29333/include\map(111): note: see reference to function template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Tree<std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>>>(const std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>> &,_Any_alloc &&)' being compiled
with
[
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Alloc=std::allocator<std::pair<const float,S>>,
_Any_alloc=std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<std::allocator<std::pair<const float,S>>>::void_pointer>>
]
C:/data/msvc/14.28.29333/include\map(111): note: see reference to function template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Tree<std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<_Alloc>::void_pointer>>>(const std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>> &,_Any_alloc &&)' being compiled
with
[
_Kty=float,
_Ty=S,
_Pr=std::less<float>,
_Alloc=std::allocator<std::pair<const float,S>>,
_Any_alloc=std::allocator<std::_Tree_node<std::pair<const float,S>,std::_Default_allocator_traits<std::allocator<std::pair<const float,S>>>::void_pointer>>
]
C:/data/msvc/14.28.29333/include\map(111): note: while compiling class template member function 'std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>::map(const std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>> &)'
C:/data/msvc/14.28.29333/include\xmemory(701): note: see reference to function template instantiation 'std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>::map(const std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>> &)' being compiled
C:/data/msvc/14.28.29333/include\vector(687): note: see reference to class template instantiation 'std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>' being compiled
C:/data/msvc/14.28.29333/include\vector(705): note: see reference to function template instantiation 'void std::vector<std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>,std::allocator<std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>>>::_Emplace_back_with_unused_capacity<>(void)' being compiled
<source>(12): note: see reference to function template instantiation 'void std::vector<std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>,std::allocator<std::map<float,S,std::less<float>,std::allocator<std::pair<const float,S>>>>>::emplace_back<>(void)' being compiled
Compiler returned: 2
You can check the code in action on godbolt here: https://godbolt.org/z/qvMPYdc5q
It works in clang and GCC but not in MSVC (latest and v19.28).
I saw somewhere that MSVC requires the ctor & dtor to be noexcept for the map to use the move constructor, but even when defining noexcept ctors & dtors for the S
struct, I get the same error.
What is MSVC doing that requires a copy in this piece of code? How can I force the move here?