Не копируемые элементы в std :: vector из std :: lists - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть не копируемый класс, упрощенный следующим образом:

struct NonCopyable
{
    NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator = (const NonCopyable&) = delete;
    NonCopyable(NonCopyable&&) = default;
    NonCopyable& operator = (NonCopyable&&) = default;
};

Я храню объекты этого класса в различных std :: lists.В какой-то момент у меня есть empty std :: vector этих списков, размер которого я хотел бы изменить, чтобы он содержал фиксированное количество пустых списков.Однако это жалуется на отсутствие конструктора копирования NonCopyable, хотя (насколько я вижу) он не должен пытаться создавать какие-либо NonCopyables!

std::vector<std::list<NonCopyable>> v; // OK
v.resize(4);                           // ERROR
v.emplace_back();                      // ERROR
std::list<NonCopyable> l;              // OK
v.push_back(l);                        // ERROR (unsurprisingly)
v.push_back(std::move(l));             // ERROR

Почему это так?Есть ли способ сделать это, не делая класс копируемым?

Я использую VS2017 с / std: c ++ 17 на случай, если что-то изменится.


Вотполный вывод ошибок при попытке изменить размер (первые две строки выше).

1>------ Build started: Project: testcore, Configuration: Debug x64 ------
1>testcard.cpp
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\xmemory0(881): error C2280: 'NonCopyable::NonCopyable(const NonCopyable &)': attempting to reference a deleted function
1>[...]\testcard.cpp(30): note: see declaration of 'NonCopyable::NonCopyable'
1>[...]\testcard.cpp(30): note: 'NonCopyable::NonCopyable(const NonCopyable &)': function was explicitly deleted
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(711): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const NonCopyable&>(_Alloc &,_Objty *const ,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Alloc=std::allocator<std::_List_node<NonCopyable,std::_Default_allocator_traits<std::allocator<NonCopyable>>::void_pointer>>,
1>            _Ty=NonCopyable,
1>            _Objty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(716): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const NonCopyable&>(_Alloc &,_Objty *const ,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Alloc=std::allocator<std::_List_node<NonCopyable,std::_Default_allocator_traits<std::allocator<NonCopyable>>::void_pointer>>,
1>            _Ty=NonCopyable,
1>            _Objty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(947): note: see reference to function template instantiation 'std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_List_buy<_Ty,_Alloc>::_Buynode<const NonCopyable&>(std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *,std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Alloc=std::allocator<NonCopyable>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(950): note: see reference to function template instantiation 'std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *std::_List_buy<_Ty,_Alloc>::_Buynode<const NonCopyable&>(std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *,std::_List_node<_Ty,std::_Default_allocator_traits<_Alloc>::void_pointer> *,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Alloc=std::allocator<NonCopyable>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(1308): note: see reference to function template instantiation 'void std::list<NonCopyable,std::allocator<_Ty>>::_Insert<const NonCopyable&>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>,std::_Iterator_base0>,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(1308): note: see reference to function template instantiation 'void std::list<NonCopyable,std::allocator<_Ty>>::_Insert<const NonCopyable&>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>,std::_Iterator_base0>,const NonCopyable &)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(1265): note: see reference to function template instantiation 'void std::list<NonCopyable,std::allocator<_Ty>>::_Insert_range<_Iter>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>,std::_Iterator_base0>,_Iter,_Iter,std::forward_iterator_tag)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<NonCopyable>>>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(1264): note: see reference to function template instantiation 'void std::list<NonCopyable,std::allocator<_Ty>>::_Insert_range<_Iter>(std::_List_unchecked_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>,std::_Iterator_base0>,_Iter,_Iter,std::forward_iterator_tag)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<NonCopyable>>>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(800): note: see reference to function template instantiation 'std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>> std::list<_Ty,std::allocator<_Ty>>::insert<std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,void>(std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,_Iter,_Iter)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<NonCopyable>>>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(800): note: see reference to function template instantiation 'std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>> std::list<_Ty,std::allocator<_Ty>>::insert<std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,void>(std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,_Iter,_Iter)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable,
1>            _Iter=std::_List_const_iterator<std::_List_val<std::_List_simple_types<NonCopyable>>>
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\list(796): note: while compiling class template member function 'std::list<NonCopyable,std::allocator<_Ty>>::list(const std::list<_Ty,std::allocator<_Ty>> &)'
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\xmemory0(881): note: see reference to function template instantiation 'std::list<NonCopyable,std::allocator<_Ty>>::list(const std::list<_Ty,std::allocator<_Ty>> &)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\vector(1812): note: see reference to class template instantiation 'std::list<NonCopyable,std::allocator<_Ty>>' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\vector(1811): note: while compiling class template member function 'std::list<NonCopyable,std::allocator<_Ty>> *std::vector<std::list<_Ty,std::allocator<_Ty>>,std::allocator<std::list<_Ty,std::allocator<_Ty>>>>::_Udefault(std::list<_Ty,std::allocator<_Ty>> *,const unsigned __int64)'
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\vector(1479): note: see reference to function template instantiation 'std::list<NonCopyable,std::allocator<_Ty>> *std::vector<std::list<_Ty,std::allocator<_Ty>>,std::allocator<std::list<_Ty,std::allocator<_Ty>>>>::_Udefault(std::list<_Ty,std::allocator<_Ty>> *,const unsigned __int64)' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>[...]\testcard.cpp(37): note: see reference to class template instantiation 'std::vector<std::list<NonCopyable,std::allocator<_Ty>>,std::allocator<std::list<_Ty,std::allocator<_Ty>>>>' being compiled
1>        with
1>        [
1>            _Ty=NonCopyable
1>        ]
1>Done building project "testcore.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

std::list является не noexcept-movable , но копируемый.Следовательно, std::vector предпочитает list конструктор копирования, а не его конструктор перемещения, независимо от того.

Чтобы обойти эту проблему, вы должны обернуть std::list в класс, который не подлежит копированию.

0 голосов
/ 22 ноября 2018

Как отметил @ j6t, кажется, что это невозможно сделать.Вектор с std::list с не копируемыми элементами не может быть расширен в соответствии со стандартом (...).Если бы это был мой частный проект, я бы на самом деле рассмотрел что-то вроде этого:

#include <iostream>
#include <vector>
#include <list>

namespace xxx {
    // <flame_bait>
    template<class T, class Enable = void>
    struct list : std::list<T> {
        list() : std::list<T>() {}
        list(list&&) = default;
        list& operator=(list&&) = default;
        list(const list&) = delete;
        list& operator=(const list&) = delete;
    };

    template<class T>
    struct list<T, typename std::enable_if<std::is_copy_constructible<T>::value>::type> : std::list<T> {};
    // </flame_bait>
}

struct NonCopyable
{
    int m_id;
    NonCopyable(int id = 0) : m_id(id) {}
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator = (const NonCopyable&) = delete;
    NonCopyable(NonCopyable&&) noexcept = default;
    NonCopyable& operator = (NonCopyable&&) noexcept = default;
    ~NonCopyable() = default;
    friend std::ostream& operator<<(std::ostream&, const NonCopyable&);
};

std::ostream& operator<<(std::ostream& os, const NonCopyable& nc) {
    os << "I am not a free man, I am number " << nc.m_id;
    return os;
}

int main() {
    std::vector<xxx::list<NonCopyable>> v;
    v.resize(4);                    // now working 

    int id = 0;
    for (auto& l : v) {
        l.emplace_back(++id);       // emplace_back one NonCopyable per list  
    }

    xxx::list<NonCopyable> li;      // Create a separate list
    li.emplace_back(++id);          // create one...
    v.emplace_back(std::move(li));  // and move list to vector is now working

    for (auto& l : v) {
        for (auto& nc : l) {
            std::cout << nc << "\n";
        }
    }
}

Ожидаемый результат:

I am not a free man, I am number 1
I am not a free man, I am number 2
I am not a free man, I am number 3
I am not a free man, I am number 4
I am not a free man, I am number 5
...