我正在编写一个内部循环,需要将 struct
s 放置在连续存储中。我不知道这些 struct
中有多少会提前。我的问题是 STL 的 vector
将其值初始化为 0,所以无论我做什么,都会产生初始化成本加上设置 struct
成员的成本他们的值(value)观。
有什么方法可以阻止初始化,还是有一个类似 STL 的容器,带有可调整大小的连续存储和未初始化的元素?
(我确信这部分代码需要优化,而且我确信初始化是一笔不小的开销。)
另外,请参阅下面的评论以了解初始化发生的时间。
一些代码:
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
必须以某种方式初始化数组中的值,这意味着必须调用一些构造函数(或复制构造函数)。 vector
(或任何容器类)的行为如果您要访问数组的未初始化部分,就好像它已初始化一样。
最好的办法是使用reserve()
和push_back()
,这样就使用了copy-constructor,避免了default-constructor。
使用您的示例代码:
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]));
}
}
像这样调用 reserve()
(或 resize()
)的唯一问题是,您最终可能会比您需要的更频繁地调用复制构造函数.如果您可以对数组的最终大小做出很好的预测,最好在开始时将空间 reserve()
一次。但是,如果您不知道最终大小,则至少平均份数会最少。
在当前版本的 C++ 中,内部循环有点低效,因为临时值在堆栈上构造,复制构造到 vector 内存,最后临时值被销毁。然而,下一版本的 C++ 有一个称为 R-Value 引用 (T&&
) 的功能,它会有所帮助。
std::vector
提供的接口(interface)不允许其他选项,即使用一些类似工厂的类来构造默认值以外的值。下面是这个模式在 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));
}
}
这样做确实意味着您必须创建自己的 vector 类。在这种情况下,它也使本来应该是一个简单的例子变得复杂。但有时使用这样的工厂函数可能会更好,例如,如果插入以某个其他值为条件,那么您将不得不无条件地构造一些昂贵的临时函数,即使它实际上并不需要。
关于c++ - 存储未初始化的 STL vector ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/96579/