{"action":"created","issue":{"url":"https://api.github.com/repos/electronicarts/EASTL/issues/56","repository_url":"https://api.github.com/repos/electronicarts/EASTL","labels_url":"https://api.github.com/repos/electronicarts/EASTL/issues/56/labels{/name}","comments_url":"https://api.github.com/repos/electronicarts/EASTL/issues/56/comments","events_url":"https://api.github.com/repos/electronicarts/EASTL/issues/56/events","html_url":"https://github.com/electronicarts/EASTL/issues/56","id":177640706,"number":56,"title":"Cannot move assign a eastl::vector<unique_ptr<int>>","user":{"login":"xaxxon","id":143986,"avatar_url":"https://avatars.githubusercontent.com/u/143986?v=3","gravatar_id":"","url":"https://api.github.com/users/xaxxon","html_url":"https://github.com/xaxxon","followers_url":"https://api.github.com/users/xaxxon/followers","following_url":"https://api.github.com/users/xaxxon/following{/other_user}","gists_url":"https://api.github.com/users/xaxxon/gists{/gist_id}","starred_url":"https://api.github.com/users/xaxxon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xaxxon/subscriptions","organizations_url":"https://api.github.com/users/xaxxon/orgs","repos_url":"https://api.github.com/users/xaxxon/repos","events_url":"https://api.github.com/users/xaxxon/events{/privacy}","received_events_url":"https://api.github.com/users/xaxxon/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-09-18T09:10:52Z","updated_at":"2016-09-18T10:52:40Z","closed_at":null,"body":"```\r\n#include <memory>\r\n#include <vector>\r\n#include <EASTL/vector.h>\r\n\r\nint main(int, char**) {\r\n\r\n  // Works                                                                                                                         \r\n  std::vector<std::unique_ptr<int>> stdv1;\r\n  std::vector<std::unique_ptr<int>> stdv2;\r\n  stdv2 = std::move(stdv1);\r\n\r\n  // Doesn't work                                                                                                                  \r\n  eastl::vector<std::unique_ptr<int>> v1;\r\n  eastl::vector<std::unique_ptr<int>> v2;\r\n  v2 = std::move(v1);\r\n\r\n}\r\n\r\n\r\n```\r\n\r\nThe output on os x clang 3.9:\r\n```\r\n\r\nclang++ -std=c++14 eastl-vector-move.cpp \r\nIn file included from eastl-vector-move.cpp:3:\r\nIn file included from /usr/local/include/EASTL/vector.h:42:\r\n/usr/local/include/EASTL/memory.h:605:34: error: call to implicitly-deleted copy constructor of 'value_type' (aka\r\n      'std::__1::unique_ptr<int, std::__1::default_delete<int> >')\r\n                                        ::new((void*)&*currentDest) value_type(*first);\r\n                                                                    ^          ~~~~~~\r\n/usr/local/include/EASTL/memory.h:705:52: note: in instantiation of function template specialization\r\n      'eastl::Internal::uninitialized_copy_impl<eastl::generic_iterator<std::__1::unique_ptr<int, std::__1::default_delete<int> >\r\n      *, void>, eastl::generic_iterator<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, void> >' requested here\r\n                const generic_iterator<Result, void> i(Internal::uninitialized_copy_impl(eastl::generic_iterator<First, voi...\r\n                                                                 ^\r\n/usr/local/include/EASTL/vector.h:578:18: note: in instantiation of function template specialization\r\n      'eastl::uninitialized_copy_ptr<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> > *, std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here\r\n                mpEnd = eastl::uninitialized_copy_ptr(x.mpBegin, x.mpEnd, mpBegin);\r\n                               ^\r\n/usr/local/include/EASTL/vector.h:1733:13: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::vector' requested here\r\n                this_type temp(*this);  // This is the simplest way to accomplish this, \r\n                          ^\r\n/usr/local/include/EASTL/vector.h:685:5: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::DoClearCapacity' requested here\r\n                                DoClearCapacity(); // To consider: Are we really required to clear here? x is going away so...\r\n                                ^\r\neastl-vector-move.cpp:8:6: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::operator=' requested here\r\n  v2 = std::move(v1);\r\n     ^\r\n/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:2600:31: note: copy constructor is implicitly deleted because\r\n      'unique_ptr<int, std::__1::default_delete<int> >' has a user-declared move constructor\r\n    _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT\r\n                              ^\r\nIn file included from eastl-vector-move.cpp:3:\r\nIn file included from /usr/local/include/EASTL/vector.h:40:\r\nIn file included from /usr/local/include/EASTL/algorithm.h:237:\r\n/usr/local/include/EASTL/internal/copy_help.h:73:13: error: object of type 'std::__1::unique_ptr<int, std::__1::default_delete<int>\r\n      >' cannot be assigned because its copy assignment operator is implicitly deleted\r\n                                *result = *first;\r\n                                        ^\r\n/usr/local/include/EASTL/internal/copy_help.h:135:67: note: in instantiation of function template specialization\r\n      'eastl::move_and_copy_helper<eastl::random_access_iterator_tag, false, false>::move_or_copy<const std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> > *, std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here\r\n                return eastl::move_and_copy_helper<IIC, isMove, canBeMemmoved>::move_or_copy(first, last, result); // Need ...\r\n                                                                                ^\r\n/usr/local/include/EASTL/internal/copy_help.h:143:32: note: in instantiation of function template specialization\r\n      'eastl::move_and_copy_chooser<false, const std::__1::unique_ptr<int, std::__1::default_delete<int> > *,\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here\r\n                return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_ite...\r\n                                             ^\r\n/usr/local/include/EASTL/internal/copy_help.h:193:17: note: in instantiation of function template specialization\r\n      'eastl::move_and_copy_unwrapper<false, const std::__1::unique_ptr<int, std::__1::default_delete<int> > *,\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here\r\n                return eastl::move_and_copy_unwrapper<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result);\r\n                              ^\r\n/usr/local/include/EASTL/vector.h:1543:35: note: in instantiation of function template specialization 'eastl::copy<const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::unique_ptr<int, std::__1::default_delete<int> > *>'\r\n      requested here\r\n                        pointer const pNewEnd = eastl::copy(first, last, mpBegin); // Since we are copying to mpBegin, we d...\r\n                                                       ^\r\n/usr/local/include/EASTL/vector.h:1480:3: note: in instantiation of function template specialization\r\n      'eastl::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, eastl::allocator>::DoAssignFromIterator<const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, false>' requested here\r\n                DoAssignFromIterator<InputIterator, bMove>(first, last, IC());\r\n                ^\r\n/usr/local/include/EASTL/vector.h:660:4: note: in instantiation of function template specialization\r\n      'eastl::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, eastl::allocator>::DoAssign<const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, false>' requested here\r\n                        DoAssign<const_iterator, false>(x.begin(), x.end(), eastl::false_type());\r\n                        ^\r\n/usr/local/include/EASTL/vector.h:1393:10: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::operator=' requested here\r\n                        *this = x;                   // itself call this member swap function.\r\n                              ^\r\n/usr/local/include/EASTL/vector.h:686:5: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::swap' requested here\r\n                                swap(x);           // member swap handles the case that x has a different allocator than ou...\r\n                                ^\r\neastl-vector-move.cpp:8:6: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::operator=' requested here\r\n  v2 = std::move(v1);\r\n     ^\r\n/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:2600:31: note: copy assignment operator is implicitly deleted\r\n      because 'unique_ptr<int, std::__1::default_delete<int> >' has a user-declared move constructor\r\n    _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT\r\n                              ^\r\nIn file included from eastl-vector-move.cpp:3:\r\nIn file included from /usr/local/include/EASTL/vector.h:42:\r\n/usr/local/include/EASTL/memory.h:605:34: error: call to implicitly-deleted copy constructor of 'value_type' (aka\r\n      'std::__1::unique_ptr<int, std::__1::default_delete<int> >')\r\n                                        ::new((void*)&*currentDest) value_type(*first);\r\n                                                                    ^          ~~~~~~\r\n/usr/local/include/EASTL/memory.h:705:52: note: in instantiation of function template specialization\r\n      'eastl::Internal::uninitialized_copy_impl<eastl::generic_iterator<const std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> > *, void>, eastl::generic_iterator<std::__1::unique_ptr<int, std::__1::default_delete<int> >\r\n      *, void> >' requested here\r\n                const generic_iterator<Result, void> i(Internal::uninitialized_copy_impl(eastl::generic_iterator<First, voi...\r\n                                                                 ^\r\n/usr/local/include/EASTL/vector.h:1551:19: note: in instantiation of function template specialization\r\n      'eastl::uninitialized_copy_ptr<const std::__1::unique_ptr<int, std::__1::default_delete<int> > *, const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::unique_ptr<int, std::__1::default_delete<int> > *>'\r\n      requested here\r\n                        mpEnd = eastl::uninitialized_copy_ptr(position, last, mpEnd);\r\n                                       ^\r\n/usr/local/include/EASTL/vector.h:1480:3: note: in instantiation of function template specialization\r\n      'eastl::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, eastl::allocator>::DoAssignFromIterator<const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, false>' requested here\r\n                DoAssignFromIterator<InputIterator, bMove>(first, last, IC());\r\n                ^\r\n/usr/local/include/EASTL/vector.h:660:4: note: in instantiation of function template specialization\r\n      'eastl::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, eastl::allocator>::DoAssign<const\r\n      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, false>' requested here\r\n                        DoAssign<const_iterator, false>(x.begin(), x.end(), eastl::false_type());\r\n                        ^\r\n/usr/local/include/EASTL/vector.h:1393:10: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::operator=' requested here\r\n                        *this = x;                   // itself call this member swap function.\r\n                              ^\r\n/usr/local/include/EASTL/vector.h:686:5: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::swap' requested here\r\n                                swap(x);           // member swap handles the case that x has a different allocator than ou...\r\n                                ^\r\neastl-vector-move.cpp:8:6: note: in instantiation of member function 'eastl::vector<std::__1::unique_ptr<int,\r\n      std::__1::default_delete<int> >, eastl::allocator>::operator=' requested here\r\n  v2 = std::move(v1);\r\n     ^\r\n/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:2600:31: note: copy constructor is implicitly deleted because\r\n      'unique_ptr<int, std::__1::default_delete<int> >' has a user-declared move constructor\r\n    _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT\r\n                              ^\r\n3 errors generated.\r\n\r\n```"},"comment":{"url":"https://api.github.com/repos/electronicarts/EASTL/issues/comments/247840809","html_url":"https://github.com/electronicarts/EASTL/issues/56#issuecomment-247840809","issue_url":"https://api.github.com/repos/electronicarts/EASTL/issues/56","id":247840809,"user":{"login":"xaxxon","id":143986,"avatar_url":"https://avatars.githubusercontent.com/u/143986?v=3","gravatar_id":"","url":"https://api.github.com/users/xaxxon","html_url":"https://github.com/xaxxon","followers_url":"https://api.github.com/users/xaxxon/followers","following_url":"https://api.github.com/users/xaxxon/following{/other_user}","gists_url":"https://api.github.com/users/xaxxon/gists{/gist_id}","starred_url":"https://api.github.com/users/xaxxon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xaxxon/subscriptions","organizations_url":"https://api.github.com/users/xaxxon/orgs","repos_url":"https://api.github.com/users/xaxxon/repos","events_url":"https://api.github.com/users/xaxxon/events{/privacy}","received_events_url":"https://api.github.com/users/xaxxon/received_events","type":"User","site_admin":false},"created_at":"2016-09-18T10:52:40Z","updated_at":"2016-09-18T10:52:40Z","body":"This isn't the correct fix (if allocators don't match, it no-ops), but a change that lets the code compile is below.   However, it's unclear what should happen with a move-only value type when the allocators don't match.  \r\n\r\nhttps://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector.h#L1392\r\n\r\n\r\n\r\n```\r\n\ttemplate<class T, class... Rest, std::enable_if_t<!std::is_copy_constructible<T>::value, int> = 0>\r\n\tvoid swap_helper(eastl::vector<T, Rest...> & t1, eastl::vector<T, Rest...> & t2) {\r\n\r\n\t}\r\n\r\n\ttemplate<class T, class... Rest, std::enable_if_t<std::is_copy_constructible<T>::value, int> = 0>\r\n\tvoid swap_helper(eastl::vector<T, Rest...> & t1, eastl::vector<T, Rest...> & t2) {\r\n\t\tconst eastl::vector<T, Rest...> temp(t1); // Can't call eastl::swap because that would\r\n\t\tt1 = t2;                   // itself call this member swap function.\r\n\t\tt2     = temp;\r\n\t}\r\n\r\n\t// swap exchanges the contents of two containers. With respect to the containers allocators,\r\n\t// the C11++ Standard (23.2.1/7) states that the behavior of a call to a container's swap function \r\n\t// is undefined unless the objects being swapped have allocators that compare equal or \r\n\t// allocator_traits<allocator_type>::propagate_on_container_swap::value is true (propagate_on_container_swap\r\n\t// is false by default). EASTL doesn't have allocator_traits and so this doesn't directly apply,\r\n\t// but EASTL has the effective behavior of propagate_on_container_swap = false for all allocators. \r\n\t// So EASTL swap exchanges contents but not allocators, and swap is more efficient if allocators are equivalent.\r\n\ttemplate <typename T, typename Allocator>\r\n\tinline void vector<T, Allocator>::swap(this_type& x)\r\n\t{\r\n\t\tif(mAllocator == x.mAllocator) // If allocators are equivalent...\r\n\t\t\tDoSwap(x);\r\n\t\telse // else swap the contents.\r\n\t\t{\r\n\t\t\tswap_helper(*this, x);\r\n//\t\t\tconst this_type temp(*this); // Can't call eastl::swap because that would\r\n//\t\t\t*this = x;                   // itself call this member swap function.\r\n//\t\t\tx     = temp;\r\n\t\t}\r\n\t}\r\n```"}}
{"actor":{"display_login":"xaxxon"}}