Opened 5 years ago

Last modified 5 years ago

#13405 new Bugs

Tree-based containers have troubles with move-only types.

Reported by: Mikhail Kremniov <mkremniov@…> Owned by: Ion Gaztañaga
Milestone: To Be Determined Component: container
Version: Boost 1.66.0 Severity: Problem
Keywords: Cc:

Description

Specifically, move assignment doesn't work.

E.g. test.cpp:

#include <boost/container/set.hpp>
#include <memory>

int main()
{
    boost::container::set<std::unique_ptr<int>> set1, set2;
    set2 = std::move(set1);
}

Compiling with clang 5:

$ clang++-5.0 ~/tmp/test.cpp -std=c++14 -o test -stdlib=libc++ -isystem ./boost_1_66_0
In file included from /home/brd/tmp/test.cpp:1:
In file included from ./boost_1_66_0/boost/container/set.hpp:28:
In file included from ./boost_1_66_0/boost/container/detail/tree.hpp:25:
./boost_1_66_0/boost/container/allocator_traits.hpp:415:51: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<int, std::__1::default_delete<int> >'
      {  ::new((void*)p, boost_container_new_t()) T(::boost::forward<Args>(args)...); }
                                                  ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./boost_1_66_0/boost/container/allocator_traits.hpp:360:28: note: in instantiation of function template specialization
      'boost::container::allocator_traits<boost::container::new_allocator<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree,
      true> > >::priv_construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
         allocator_traits::priv_construct(flag, a, p, ::boost::forward<Args>(args)...);
                           ^
./boost_1_66_0/boost/container/detail/node_alloc_holder.hpp:168:36: note: in instantiation of function template specialization
      'boost::container::allocator_traits<boost::container::new_allocator<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree,
      true> > >::construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
      allocator_traits<NodeAlloc>::construct
                                   ^
./boost_1_66_0/boost/container/detail/tree.hpp:389:26: note: in instantiation of function template specialization 'boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >::create_node<const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
         return m_holder.create_node(other.m_data);
                         ^
./boost_1_66_0/boost/intrusive/detail/node_cloner_disposer.hpp:65:42: note: in instantiation of member function
      'boost::container::container_detail::RecyclingCloner<boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >,
      boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >, true>::operator()' requested here
      node_ptr n = traits_->to_node_ptr(*base_t::get()(v));
                                         ^
./boost_1_66_0/boost/intrusive/rbtree_algorithms.hpp:59:20: note: in instantiation of member function
      'boost::intrusive::detail::node_cloner<boost::container::container_detail::RecyclingCloner<boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >, true>, boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>,
      boost::intrusive::algo_types::RbTreeAlgorithms, false>::operator()' requested here
      node_ptr n = base_t::get()(p);
                   ^
./boost_1_66_0/boost/intrusive/bstree_algorithms.hpp:1943:55: note: (skipping 3 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
         node_ptr insertion_point = target_sub_root = cloner(current);
                                                      ^
./boost_1_66_0/boost/intrusive/bstree.hpp:1040:27: note: in instantiation of function template specialization 'boost::intrusive::rbtree_algorithms<boost::intrusive::rbtree_node_traits<void *, true>
      >::clone<boost::intrusive::detail::node_cloner<boost::container::container_detail::RecyclingCloner<boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >, true>, boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>,
      boost::intrusive::algo_types::RbTreeAlgorithms, false>,
      boost::intrusive::detail::node_disposer<boost::container::container_detail::allocator_destroyer<boost::container::new_allocator<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int>
      >, void *, boost::container::tree_type_enum::red_black_tree, true> > >, boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true>, boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>,
      boost::intrusive::algo_types::RbTreeAlgorithms> >' requested here
         node_algorithms::clone
                          ^
./boost_1_66_0/boost/intrusive/rbtree.hpp:240:18: note: in instantiation of function template specialization
      'boost::intrusive::bstree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, boost::intrusive::algo_types::RbTreeAlgorithms,
      void>::clone_from<boost::container::container_detail::RecyclingCloner<boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >,
      boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >, true>,
      boost::container::container_detail::allocator_destroyer<boost::container::new_allocator<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true> > > >' requested here
   {  tree_type::clone_from(BOOST_MOVE_BASE(tree_type, src), cloner, disposer);  }
                 ^
./boost_1_66_0/boost/container/detail/tree.hpp:759:24: note: in instantiation of function template specialization
      'boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true,
      void>::clone_from<boost::container::container_detail::RecyclingCloner<boost::container::container_detail::node_alloc_holder<boost::container::new_allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >,
      boost::intrusive::rbtree_impl<boost::intrusive::bhtraits<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::rbtree_node_traits<void *, true>, boost::intrusive::link_mode_type::normal_link, boost::intrusive::dft_tag, 3>, void,
      boost::container::value_to_node_compare<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *, boost::container::tree_type_enum::red_black_tree, true>,
      boost::intrusive::tree_value_compare<std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::move_detail::identity<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, true> >, unsigned long, true, void> >, true>,
      boost::container::container_detail::allocator_destroyer<boost::container::new_allocator<boost::container::container_detail::tree_node<std::__1::unique_ptr<int, std::__1::default_delete<int> >, void *,
      boost::container::tree_type_enum::red_black_tree, true> > > >' requested here
         this->icont().clone_from
                       ^
./boost_1_66_0/boost/container/set.hpp:360:46: note: in instantiation of member function 'boost::container::container_detail::tree<std::__1::unique_ptr<int, std::__1::default_delete<int> >,
      boost::move_detail::identity<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::container::new_allocator<std::__1::unique_ptr<int,
      std::__1::default_delete<int> > >, boost::container::tree_opt<boost::container::tree_type_enum::red_black_tree, true> >::operator=' requested here
   {  return static_cast<set&>(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x)));  }
                                             ^
/home/brd/tmp/test.cpp:7:10: note: in instantiation of member function 'boost::container::set<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::less<std::__1::unique_ptr<int, std::__1::default_delete<int> > >,
      boost::container::new_allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >, boost::container::tree_opt<boost::container::tree_type_enum::red_black_tree, true> >::operator=' requested here
    set2 = std::move(set1);
         ^
/home/brd/soft/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04/bin/../include/c++/v1/memory:2388:3: note: copy constructor is implicitly deleted because 'unique_ptr<int, std::__1::default_delete<int> >' has a user-declared move constructor
  unique_ptr(unique_ptr&& __u) noexcept
  ^
1 error generated.

Attachments (1)

boost_container_move_fix.diff (2.9 KB ) - added by Mikhail Kremniov <mkremniov@…> 5 years ago.
Suggested fix

Download all attachments as: .zip

Change History (2)

by Mikhail Kremniov <mkremniov@…>, 5 years ago

Suggested fix

comment:1 by Mikhail Kremniov <mkremniov@…>, 5 years ago

A possible fix is attached.

Note: See TracTickets for help on using tickets.