簡體   English   中英

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

[英]Non-copyable elements in a std::vector of std::lists

我有一個不可復制的類,簡化如下:

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

我將此類的對象存儲在各種std :: lists中。 某一時刻,我有一個空的 std :: vector這些列表,我想調整其大小以包含固定數量的列表。 但是,這抱怨缺少NonCopyable復制構造函數,盡管(據我所知)它不應該嘗試構造任何NonCopyable!

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 ==========

std::list 不是noexcept-movable ,但是是可復制的。 因此,無論如何, std::vector希望list的copy-constructor優於其move-constructor。

要變通解決此問題,您必須將std::list包裝在不可復制的類中。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM