STL向量与未初始化存储? [英] STL vectors with uninitialized storage?

查看:157
本文介绍了STL向量与未初始化存储?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写一个内部循环,需要将 struct 放在连续的存储中。我不知道这些 struct 中有多少会提前。我的问题是STL的向量初始化其值为0,所以不管我做什么,我承担初始化的成本加上设置 struct 的成员到它们的值。



有任何方法来阻止初始化,或者有一个类似STL的容器与可调整大小的连续存储和未初始化的元素?



(我确定这部分代码需要优化,我确信初始化是一个重要成本。)



另外,请参阅下面的意见,了解初始化的时间。



  void GetsCalledALot(int * data1,int * data2,int count){
int mvSize = memberVector.size ()
memberVector.resize(mvSize + count); // cause 0-initialization

for(int i = 0; i memberVector [mvSize + i] .d1 = data1 [i];
memberVector [mvSize + i] .d2 = data2 [i];
}
}


解决方案

code> std :: vector 必须以某种方式初始化数组中的值,这意味着必须调用一些构造函数(或复制构造函数)。如果您要访问数组的未初始化部分,如同它被初始化一样,向量(或任何容器类)的行为是未定义的。



最好的方法是使用 reserve() push_back()


$ b 使用您的示例代码:

 

code> struct YourData {
int d1;
int d2;
YourData(int v1,int v2):d1(v1),d2(v2){}
};

std :: vector< YourData> memberVector;

void GetsCalledALot(int * data1,int * data2,int count){
int mvSize = memberVector.size();

//不初始化额外的元素
memberVector.reserve(mvSize + count);

//注意:考虑使用std :: generate_n或std :: copy而不是这个循环。
for(int i = 0; i //使用临时的复制结构。
memberVector.push_back(YourData(data1 [i],data2 [i]));
}
}

调用 reserve()(或 resize())就像这样,你可能最终调用复制构造函数比你需要更多。如果你可以对数组的最终大小做一个很好的预测,最好在开始时 reserve()一次。



在当前版本的C ++中,内层循环是一个位作为临时值在堆栈上构造,拷贝构造到向量存储器,并且最终临时被破坏。然而,下一版本的C ++有一个称为R-Value引用( T&& )的功能,这将有所帮助。



std :: vector 提供的接口不允许使用另一个选项,这是使用一些类似工厂的类来构造默认值以外的值。这里是一个粗略的例子,这个模式看起来像在C ++中实现:

  template< typename T& 
class my_vector_replacement {

// ...

template< typename F>
my_vector :: push_back_using_factory(F factory){
// ...检查数组的大小,如果需要,调整大小。

//使用placement new复制构造,
new(arrayData + end)T(factory())
end + = sizeof
}

char * arrayData;
size_t end; // arrayData中的初始化数据
};

//许多可能的实现之一
struct MyFactory {
MyFactory(int * p1,int * p2):d1(p1),d2(p2){}
YourData operator()()const {
return YourData(* d1,* d2);
}
int * dl;
int * d2;
};

void GetsCalledALot(int * data1,int * data2,int count){
// ...仍然需要对reserve()类型函数进行相同的调用。

//注意:考虑使用std :: generate_n或std :: copy而不是这个循环。
for(int i = 0; i //使用工厂复制结构
memberVector.push_back_using_factory(MyFactory(data1 + i,data2 + );
}
}

这样做意味着你必须创建自己的向量类。在这种情况下,它也使本应是一个简单的例子复杂化。但是有时候,使用这样的工厂函数更好,例如,如果插入是有条件的一些其他值,你必须无条件地构造一些昂贵的临时,即使它实际上不需要。


I'm writing an inner loop that needs to place structs in contiguous storage. I don't know how many of these structs there will be ahead of time. My problem is that STL's vector initializes its values to 0, so no matter what I do, I incur the cost of the initialization plus the cost of setting the struct's members to their values.

Is there any way to prevent the initialization, or is there an STL-like container out there with resizeable contiguous storage and uninitialized elements?

(I'm certain that this part of the code needs to be optimized, and I'm certain that the initialization is a significant cost.)

Also, see my comments below for a clarification about when the initialization occurs.

SOME CODE:

void GetsCalledALot(int* data1, int* data2, int count) {
    int mvSize = memberVector.size()
    memberVector.resize(mvSize + count); // causes 0-initialization

    for (int i = 0; i < count; ++i) {
        memberVector[mvSize + i].d1 = data1[i];
        memberVector[mvSize + i].d2 = data2[i];
    }
}

解决方案

std::vector must initialize the values in the array somehow, which means some constructor (or copy-constructor) must be called. The behavior of vector (or any container class) is undefined if you were to access the uninitialized section of the array as if it were initialized.

The best way is to use reserve() and push_back(), so that the copy-constructor is used, avoiding default-construction.

Using your example code:

struct YourData {
    int d1;
    int d2;
    YourData(int v1, int v2) : d1(v1), d2(v2) {}
};

std::vector<YourData> memberVector;

void GetsCalledALot(int* data1, int* data2, int count) {
    int mvSize = memberVector.size();

    // Does not initialize the extra elements
    memberVector.reserve(mvSize + count);

    // Note: consider using std::generate_n or std::copy instead of this loop.
    for (int i = 0; i < count; ++i) {
        // Copy construct using a temporary.
        memberVector.push_back(YourData(data1[i], data2[i]));
    }
}

The only problem with calling reserve() (or resize()) like this is that you may end up invoking the copy-constructor more often than you need to. If you can make a good prediction as to the final size of the array, it's better to reserve() the space once at the beginning. If you don't know the final size though, at least the number of copies will be minimal on average.

In the current version of C++, the inner loop is a bit inefficient as a temporary value is constructed on the stack, copy-constructed to the vectors memory, and finally the temporary is destroyed. However the next version of C++ has a feature called R-Value references (T&&) which will help.

The interface supplied by std::vector does not allow for another option, which is to use some factory-like class to construct values other than the default. Here is a rough example of what this pattern would look like implemented in C++:

template <typename T>
class my_vector_replacement {

    // ...

    template <typename F>
    my_vector::push_back_using_factory(F factory) {
        // ... check size of array, and resize if needed.

        // Copy construct using placement new,
        new(arrayData+end) T(factory())
        end += sizeof(T);
    }

    char* arrayData;
    size_t end; // Of initialized data in arrayData
};

// One of many possible implementations
struct MyFactory {
    MyFactory(int* p1, int* p2) : d1(p1), d2(p2) {}
    YourData operator()() const {
        return YourData(*d1,*d2);
    }
    int* d1;
    int* d2;
};

void GetsCalledALot(int* data1, int* data2, int count) {
    // ... Still will need the same call to a reserve() type function.

    // Note: consider using std::generate_n or std::copy instead of this loop.
    for (int i = 0; i < count; ++i) {
        // Copy construct using a factory
        memberVector.push_back_using_factory(MyFactory(data1+i, data2+i));
    }
}

Doing this does mean you have to create your own vector class. In this case it also complicates what should have been a simple example. But there may be times where using a factory function like this is better, for instance if the insert is conditional on some other value, and you would have to otherwise unconditionally construct some expensive temporary even if it wasn't actually needed.

这篇关于STL向量与未初始化存储?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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