Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在std::vector中存储对象而不复制或移动构造函数?_C++_C++11_Vector_Constructor_Move - Fatal编程技术网

C++ 如何在std::vector中存储对象而不复制或移动构造函数?

C++ 如何在std::vector中存储对象而不复制或移动构造函数?,c++,c++11,vector,constructor,move,C++,C++11,Vector,Constructor,Move,为了提高std::vector的效率,它的底层数组需要预先分配,有时需要重新分配。但是,这需要创建并在以后移动T类型的对象,并使用复制ctor或移动ctor 我遇到的问题是,T无法复制或移动,因为它包含无法复制或移动的对象(例如原子和互斥体)。(是的,我正在实现一个简单的线程池。) 我希望避免使用指针,因为: 我不需要一个间接的层次,所以我不想要一个 (指针的效率较低,并且增加了复杂性。使用指针会增加内存碎片并减少数据局部性,这可能(但不一定)会对性能产生显著影响。虽然不是很重要,但仍然值得考虑

为了提高std::vector的效率,它的底层数组需要预先分配,有时需要重新分配。但是,这需要创建并在以后移动
T
类型的对象,并使用复制ctor或移动ctor

我遇到的问题是,
T
无法复制或移动,因为它包含无法复制或移动的对象(例如
原子
互斥体
)。(是的,我正在实现一个简单的线程池。)

我希望避免使用指针,因为:

  • 我不需要一个间接的层次,所以我不想要一个
  • (指针的效率较低,并且增加了复杂性。使用指针会增加内存碎片并减少数据局部性,这可能(但不一定)会对性能产生显著影响。虽然不是很重要,但仍然值得考虑。)
  • 有没有办法避免一定程度的间接性


    更新:我修正了一些不正确的假设,并根据评论和答案中的反馈重新表述了问题。

    首先,
    std::mutex
    无法复制或移动,因此您不得不使用某种间接方式

    由于您希望将互斥体存储在向量中,而不是复制它,因此我将使用
    std::unique\u ptr

    vector
    不允许某些向量操作(例如针对每个向量)

    我不确定我是否理解那句话。完全可以对以下各项执行范围:

    std::vector< std::unique_ptr< int > > v;
    // fill in the vector
    for ( auto & it : v )
      std::cout << *it << std::endl;
    
    std::vector>v;
    //填充向量
    用于(自动和it:v)
    std::cout v;
    v、 后置炮台(新int(3));
    v、 后置炮台(新int(5));
    std::for_each(v.begin()、v.end()、[](const std::unique_ptr&it){std::cout
    但是,这需要创建具有复制ctor的T类型的对象

    这并不完全正确,从C++11开始,如果您使用
    std::vector
    的构造函数,它将默认构造许多元素,那么您就不需要复制或移动构造函数

    因此,如果没有从池中添加或删除线程,则可以执行以下操作:

    int num = 23;
    std::vector<std::mutex> vec(num);
    

    最后,请注意,
    std::thread
    当然是可移动的,因此您可以使用
    std::vector
    +
    std::vector::emplace_back

    总结到目前为止提出的建议:

  • 使用
    vector
    ——添加显式间接级别,这是OP不需要的
  • 使用
    deque
    ——我第一次尝试了
    deque
    ,但是从中删除对象也不起作用
  • 解决方案是使用单链表(或者如果你想使用双链表,也可以使用)。正如@JanHudec指出的,
    vector
    (以及它的许多朋友)添加或删除项目时需要重新分配。这与不允许复制或移动的对象(如
    mutex
    atomic
    )不匹配。
    forward\u list
    list
    不需要重新分配,因为每个单元格都是独立分配的(我不能引用这方面的标准,但索引方法引起了这一假设)。由于它们实际上是链表,它们不支持随机访问索引。
    myList.begin()+I
    将为您提供
    I
    第四个元素的迭代器,但它(最肯定)必须首先循环所有以前的
    i
    单元格

    我还没有看过标准的承诺,但在Windows(Visual Studio)和CompileOnline(g++)上运行良好。请随意在上使用以下测试用例:

    我希望它的性能与
    vector
    大致相同(只要不经常使用随机访问索引)

    警告:使用
    转发列表::删除当前在VS 2012中不起作用。这是因为它在尝试删除元素之前复制了元素。头文件
    Microsoft Visual Studio 11.0\VC\include\forward\u列表
    (与
    列表
    中的问题相同)显示:

    因此,它被复制“以防一路上被删除”。这意味着
    list
    forward\u list
    甚至不允许存储
    unique\u ptr
    。我认为这是一个设计缺陷

    解决方法很简单:如果
    ,则必须使用
    remove\u,而不是
    remove
    ,因为该函数的实现不会复制任何内容

    很多功劳都归功于其他答案。然而,由于没有一个答案是没有指针的完整解决方案,我决定写这个答案。

    您可以在
    std::vector
    中存储元素,而无需移动或复制构造函数,但您只需避免使用需要元素具有移动或复制构造函数的方法。几乎1任何改变向量大小的操作(例如,
    向后推
    调整大小()
    ,等等)

    实际上,这意味着您需要在构造时分配一个固定大小的向量,这将调用对象的默认构造函数,您可以通过赋值对其进行修改。这至少适用于可以被赋值的
    std::atomic
    对象



    1
    clear()
    是不需要复制/移动构造函数的大小更改方法的唯一示例,因为它从不需要移动或复制任何元素(毕竟,此操作后向量为空)。当然,调用此函数后,您再也不能增长零大小的向量了!

    如果您可以容忍所有线程池对象都是默认构造的,而不是提供除ctor/dtor之外的其他方法使它们活/死,那么
    std::array
    会起作用吗?我认为for_每个都适合向量成员,只要您是sing reference访问成员。预分配不是问题。内存已预分配,但对象已打开
    int num = 23;
    std::vector<std::mutex> vec(num);
    
    std::deque<std::mutex> deq;
    deq.emplace_back();
    deq.emplace_back();
    
    for(auto& m : deq) {
        m.lock();
    }
    
    #include <forward_list>
    #include <iostream>
    #include <mutex>
    #include <algorithm>
    
    using namespace std;
    
    class X
    {
        /// Private copy constructor.
        X(const X&);
        /// Private assignment operator.
        X& operator=(const X&);
    
    public:
        /// Some integer value
        int val;
        /// An object that can be neither copied nor moved
        mutex m;
    
        X(int val) : val(val) { }
    };
    
    
    int main()
    {
        // create list
        forward_list<X> xList;
    
        // add some items to list
        for (int i = 0; i < 4; ++i)
           xList.emplace_front(i);
    
        // print items
        for (auto& x : xList)
           cout << x.val << endl;
    
        // remove element with val == 1    
        // WARNING: Must not use remove here (see explanation below)
        xList.remove_if([](const X& x) { return x.val == 1; });
    
    
        cout << endl << "Removed '1'..." << endl << endl;
    
        for (auto& x : xList)
           cout << x.val << endl;
    
       return 0;
    }
    
    Executing the program....
    $demo 
    3
    2
    1
    0
    
    Removed '1'...
    
    3
    2
    0
    
    void remove(const _Ty& _Val_arg)
    {   // erase each element matching _Val
        const _Ty _Val = _Val_arg;  // in case it's removed along the way
    
        // ...
    }