我有一段代码可以创建数千个对象,并将它们附加到向量中。 下面的代码只是正在做的事情的一个例子,即使构造函数有一些参数,并且for实际上没有那个条件,但它的目的是显示它运行了数千次。
vector<VolumeInformation*> vector = vector<VolumeInformation*>();
for (int i = 0; i < 5000; ++i) {
VolumeInformation* info = new VolumeInformation();
vector.push_back(info);
}
代码需要花费大量时间才能运行,我试图找到一种更快的方法来创建所有对象。我读到了有关块分配器的内容,但我不确定这是否真正意味着我要做的事情,以及它是否真的有助于更快地完成这项工作。我想为一千个对象分配内存(例如),并在它仍然可用时继续使用该内存,然后在需要时分配更多内存,避免每次都为单个对象分配内存。可以这样做吗?你能指点我到哪里可以找到一个关于如何告诉'new'使用以前分配的内存的例子吗?如果不是对象本身,可以将分配器用于向量的内存(即使对象真的需要加速)吗?
谢谢。
**更新**
在所有答案和评论之后,我决定对代码进行更改,因此向量将存储对象而不是指针,因此我可以使用reserve为向量预先分配一些内存,从而可以节省一些通过一次为多个对象实例分配内存的时间。虽然在做了一些性能基准之后,我确认我所做的更改表现得更糟,除非我提前知道向量的确切大小。以下是我的调查结果,我想知道是否有人可以阐明这一点,让我知道为什么会发生这种情况,如果我在这里遗漏了什么,或者我以前使用的方法是否真的是最好的。
以下是我用于基准测试的代码:
vector<int> v = vector<int>();
v.push_back(1);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(7);
v.push_back(9);
int testAmount = 200000;
int reserve = 500000;
Stopwatch w = Stopwatch();
w = Stopwatch();
vector<VolumeInformation> infos = vector<VolumeInformation>();
infos.reserve(reserve);
for (int i = 0; i < testAmount; ++i) {
infos.emplace_back(&v, 1, 0, 0);
}
int elapsed = w.Elapsed();
w = Stopwatch();
vector<VolumeInformation*> infoPointers = vector<VolumeInformation*>();
infoPointers.reserve(reserve);
for (int i = 0; i < testAmount; ++i) {
infoPointers.emplace_back(new VolumeInformation(&v, 1, 0, 0));
}
int elapsed2 = w.Elapsed();
如果我注释掉两个reserve()行,没有指针的版本需要32.701秒,而指针版本需要6.159!它比使用对象矢量少了5倍。
如果我使用reserve,但将要保留的项目数量设置为低于迭代次数的值,则对象向量版本仍然需要比指针版本更多的时间。
如果我使用值大于或等于迭代量的reserve,则对象版本的向量变得快得多,仅需要270ms,而指针版本只需8.901秒。这里的主要问题是我事先并不知道向量将达到的大小,因为迭代不是基于硬编码的数字,这只是为了进行基准测试。
有人可以解释为什么会发生这种情况,如果有另一种解决方法,或者我在这里做错了什么?
答案 0 :(得分:2)
你可能希望在循环之前为你的5000个元素提供reserve
空间:
vector.reserve(5000);
for (int i = 0; i < 5000; ++i) {
VolumeInformation info = new VolumeInformation();
vector.push_back(info);
}
这可以通过消除多个resize
来节省时间,因为vector
增长,如果VolumeInformation
需要花费很多时间(及时)来复制。
答案 1 :(得分:2)
vector
完全能够预先分配大块并将其用于所有元素,如果你只是正确使用它:
// create 5000 default-constructed X objects
std::vector<X> v(5000);
或者如果你需要传递构造函数参数:
std::vector<X> v;
v.reserve(5000); // allocate block of memory for 5000 objects
for (int i=0 ; i < v.size(); ++i)
v.emplace_back(arg1, arg2, i % 2 ? arg3 : arg4);
最后一行在预先分配的内存中构造X
,没有复制,将函数参数传递给X构造函数。
我想为一千个对象分配内存(例如),并在它仍然可用时继续使用该内存,然后在需要时分配更多内存,避免每次都为单个对象分配内存。
std::vector
自动执行此操作,您可能应该停止使用new
并且只有vector<VolumeInformation>
并直接将对象放入其中,而不是分配单个对象并存储指针。< / p>
内存分配很慢(请参阅Why should C++ programmers minimize use of 'new'?),因此请停止分配单个对象。上面的两个示例都将执行 1 分配和5000个构造函数调用。您的原始代码执行至少5001次分配和5000次构造函数调用(在典型的C ++实现中,它将执行 5013分配和5000次构造函数调用)。
** 更新 **
如果我注释掉两个reserve()行,没有指针的版本需要32.701秒,而指针版本需要6.159!它比使用对象矢量少了5倍。
由于您实际上没有显示完整的工作程序,因此您要求人们猜测(始终显示实际代码!)但它表明您的类具有非常慢速复制构造函数,这是当向量增长并且需要将现有元素复制到新内存时(旧元素随后被销毁)使用。
如果你可以添加一个比复制构造函数更高效的noexcept
移动构造函数,那么当向量需要增长并且运行速度更快时,std::vector
将使用它。
这里的主要问题是我事先并不知道向量将达到的大小,因为迭代不是基于硬编码的数字,这只是为了进行基准测试。
您可以保留比您可能需要的更多元素,更高的内存使用率以获得更好的性能。