std :: lists的std :: vector中的不可复制元素

时间:2018-11-22 13:25:38

标签: c++ c++11 stl

我有一个不可复制的类,简化如下:

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,我想调整其大小以包含固定数量的 empty 列表。但是,这抱怨缺少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 :(得分:3)

std::listnot noexcept-movable,但可以复制。因此,std::vector首选list的copy-constructor而不是其move-constructor。

要解决此问题,您必须将std::list包装在不可复制的类中。

答案 1 :(得分:2)

正如@ 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