如何在不复制对象的情况下存储对象或在std :: vector中移动构造函数? [英] How to store objects without copy or move constructor in std::vector?

查看:152
本文介绍了如何在不复制对象的情况下存储对象或在std :: vector中移动构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了提高std::vector<T>的效率,它的基础数组需要预先分配,有时需要重新分配.但是,这需要使用复制ctor或移动ctor创建和移动T类型的对象.

To improve efficiency of std::vector<T>, it's underlying array needs to be pre-allocated and sometimes re-allocated. That, however, requires the creation and later moving of objects of type T with a copy ctor or move ctor.

我遇到的问题是T无法复制或移动,因为它包含无法复制或移动的对象(例如atomicmutex). (而且,是的,我正在实现一个简单的线程池.)

The problem that I am having is that T cannot be copied or moved because it contains objects that cannot be copied or moved (such as atomic and mutex). (And, yes, I am implementing a simple thread pool.)

我想避免使用指针,因为:

I would like to avoid using pointers because:

  1. 我不需要一定程度的间接,所以我不需要.
  2. (指针的效率较低,并且增加了复杂性.使用指针会增加内存碎片并降低数据局部性,这可能(但不一定必须)会引起明显的性能影响.不是那么重要,但仍然值得考虑.)

这里有办法避免一定程度的间接访问吗?

Is there a way to avoid a level of indirection here?

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

推荐答案

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

To summarize what was proposed so far:

  1. 使用vector<unique_ptr<T>>-添加显式的间接级别,OP不需要此级别.
  2. 使用deque<T>-我首先尝试了deque,但是从中擦除对象也行不通. 查看有关 >和list.
  1. Use vector<unique_ptr<T>> -- Adds an explicit level of indirection and was unwanted by OP.
  2. Use deque<T> -- I first tried deque, but erasing objects from it also does not work. See this discussion on differences between deque and list.

解决方案是使用 forward_list ,该链接为单链接列表(也可以使用 list ) ).正如@JanHudec指出的那样,vector(及其许多朋友)在添加或删除项目时需要重新分配.对于不允许复制或移动的对象,例如mutexatomic,它的效果不佳. forward_listlist不需要这样做,因为每个单元格是独立分配的(我不能在此引用标准,但是索引方法引起了这一假设).由于它们实际上是链接列表,因此它们不支持随机访问索引. myList.begin() + i将为您提供第i个元素的迭代器,但是(最肯定的是)它将必须首先遍历所有先前的i单元格.

The solution is to use forward_list which is a singly-linked list (or you can use list if you want a doubly-linked list). As @JanHudec pointed out, vector (and many of it's friends) require re-allocation when adding or removing items. That does not sit well with objects like mutex and atomic which are not allowed to be copied nor moved. forward_list and list do not require that because each cell is allocated independently (I cannot cite the standard on that, but the indexing method gives rise to that assumption). Since they are actually linked lists, they do not support random access indexing. myList.begin() + i will get you an iterator of the i'th element, but it (most certainly) will have to loop through all previous i cells first.

我没有查看标准的承诺,但是在Windows(Visual Studio)和CompileOnline(g ++)上一切正常.随时在 CompileOnline 上试用以下测试用例:

I have not looked at the promises by the standard, but things work fine on Windows (Visual Studio) and CompileOnline (g++). Feel free to play around with the following test case on CompileOnline:

#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

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

I expect this to roughly have the same performance as vector<unique_ptr<T>> (as long as you don't use random access indexing too often).

警告:在VS 2012中,当前无法使用forward_list::remove.这是因为在尝试删除元素之前,它会先复制元素.头文件Microsoft Visual Studio 11.0\VC\include\forward_list(list中的相同问题)显示:

WARNING: Using forward_list::remove does not currently work in VS 2012. That is because it copies the element before trying to remove it. The header file Microsoft Visual Studio 11.0\VC\include\forward_list (same problem in list) reveals:

void remove(const _Ty& _Val_arg)
{   // erase each element matching _Val
    const _Ty _Val = _Val_arg;  // in case it's removed along the way

    // ...
}

因此,它被复制为以防被删除".这意味着listforward_list甚至都不允许存储unique_ptr.我认为这是一个设计错误.

So, it is copied "in case it's removed along the way". This means that list and forward_list don't even allow for storing unique_ptr. I assume that this is a design bug.

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

The work-around is simple: You have to use remove_if instead of remove because the implementation of that function does not copy anything.

其他答案有很多功劳.但是,由于它们都不是没有指针的完整解决方案,因此我决定编写此答案.

这篇关于如何在不复制对象的情况下存储对象或在std :: vector中移动构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆