C++ 在向量的每个struct元素中重置值的最快方法?
非常类似,除了我有C++ 在向量的每个struct元素中重置值的最快方法?,c++,performance,vector,C++,Performance,Vector,非常类似,除了我有vector,而不是vector 如果我想为向量中的每个元素重置(或者设置为某个值)myType.myVar,最有效的方法是什么 现在我正在迭代: for(int i=0; i<myVec.size(); i++) myVec.at(i).myVar = 0; for(int i=0;i重置将需要遍历向量的每个元素,因此它至少需要O(n)复杂度。您当前的算法需要O(n) 在这种特殊情况下,您可以使用操作符[]而不是at(这可能会引发异常)。但我怀疑这是应用程序的瓶颈 在
vector
,而不是vector
如果我想为向量中的每个元素重置(或者设置为某个值)myType.myVar
,最有效的方法是什么
现在我正在迭代:
for(int i=0; i<myVec.size(); i++) myVec.at(i).myVar = 0;
for(int i=0;i重置将需要遍历向量的每个元素,因此它至少需要O(n)复杂度。您当前的算法需要O(n)
在这种特殊情况下,您可以使用操作符[]
而不是at
(这可能会引发异常)。但我怀疑这是应用程序的瓶颈
在此说明中,您可能应该使用:
但是,除非您想进入字节级并将一块内存设置为0
,这不仅会让您头疼,而且在大多数情况下还会使您失去可移植性,否则这里没有什么可以改进的。而不是下面的代码
for(int i=0; i<myVec.size(); i++) myVec.at(i).myVar = 0;
<代码> >(int i=0;i除了前面所说的,您应该考虑如果打开优化,编译器将可能执行循环展开,这将使循环本身更快。 也就是预增量<代码> ++i 很少有比后增量<代码> I++<代码>更少的指令。
解释最快的方法之一是执行循环展开并打破传统对造成大量现金溢出的循环造成的速度限制。在您的情况下,由于这是一个运行时的事情,因此无法应用模板元编程,因此这是好的老达夫设备的一个变体e就行了
#include <iostream>
#include <vector>
using namespace std;
struct myStruct {
int a;
double b;
};
int main()
{
std::vector<myStruct> mV(20);
double val(20); // the new value you want to reset to
int n = (mV.size()+7) / 8; // 8 is the size of the block unroll
auto to = mV.begin(); //
switch(mV.size()%8)
{
case 0: do { (*to++).b = val;
case 7: (*to++).b = val;
case 6: (*to++).b = val;
case 5: (*to++).b = val;
case 4: (*to++).b = val;
case 3: (*to++).b = val;
case 2: (*to++).b = val;
case 1: (*to++).b = val;
} while (--n>0);
}
// just printing to verify that the value is set
for (auto i : mV) std::cout << i.b << std::endl;
return 0;
}
#包括
#包括
使用名称空间std;
结构myStruct{
INTA;
双b;
};
int main()
{
std::向量mV(20);
double val(20);//要重置为的新值
int n=(mV.size()+7)/8;//8是块展开的大小
自动到=mV.begin();//
开关(mV.size()%8)
{
案例0:do{(*to++)。b=val;
案例7:(*到++).b=val;
案例6:(*到++).b=val;
案例5:(*到++).b=val;
案例4:(*到++).b=val;
案例3:(*到++).b=val;
案例2:(*到++).b=val;
案例1:(*到++).b=val;
}而(-n>0);
}
//只需打印以验证值是否已设置
对于(auto i:mV)std::cout请注意不要花太多时间考虑编译器将为您处理的优化细节
下面是我理解的OP的四个实现,以及使用GCC4.8和--std=c++11-O3-S
声明:
#include <algorithm>
#include <vector>
struct T {
int irrelevant;
int relevant;
double trailing;
};
当然myVec.resize(10,{0})
是O(1)?我想知道是否有类似的方法,但在结构中保留其他变量的值。不过,谢谢!@OllieFord。不,调整大小的复杂性也是如此。好的,谢谢。我有一个后续问题,我是否可以将此合并到std::sort
的“最后一次迭代”中,以重置排序所依据的值。请告知e我是应该把它作为一个新问题发布,还是编辑细节?@OllieFord,你说的“合并”是什么意思?用词不当。在我完成基于myVal
的排序后,我想设置myVal=0
。我能在上次运行std::sort
时以某种方式做到这一点吗?很好!谢谢。at()
-我只是在知道它“更安全”的情况下才使用它。现在我也知道了(至少部分)原因:)既然我们非常喜欢微优化,你也应该存储myVec.size()
在变量中,而不是在每个循环中执行函数调用。哦,您可能也应该使用++i
而不是i++
。您知道。保存std::size\t
整数的副本可能很有用。@OllieFord:at()被调用时,它会调用size()方法,然后检查索引是否小于大小。因此,在某种程度上,在访问每个元素时调用size()的开销非常小。运算符[]access只进行指针添加和返回。我想这会有所帮助。@tmp:它正在调用size()在每次迭代中显式地调用。在循环开始之前调用它一次并将其赋值给变量。根据这个答案,C++向量实际上是连续存储的。@粘土我读到一个答案,它们现在(不能找到)。-但这有更多的投票。将进行相应的编辑,谢谢。达夫的设备并不保证性能会更快。在许多情况下,已经观察到性能会降低。
#include <iostream>
#include <vector>
using namespace std;
struct myStruct {
int a;
double b;
};
int main()
{
std::vector<myStruct> mV(20);
double val(20); // the new value you want to reset to
int n = (mV.size()+7) / 8; // 8 is the size of the block unroll
auto to = mV.begin(); //
switch(mV.size()%8)
{
case 0: do { (*to++).b = val;
case 7: (*to++).b = val;
case 6: (*to++).b = val;
case 5: (*to++).b = val;
case 4: (*to++).b = val;
case 3: (*to++).b = val;
case 2: (*to++).b = val;
case 1: (*to++).b = val;
} while (--n>0);
}
// just printing to verify that the value is set
for (auto i : mV) std::cout << i.b << std::endl;
return 0;
}
#include <algorithm>
#include <vector>
struct T {
int irrelevant;
int relevant;
double trailing;
};
.cfi_startproc
movq (%rdi), %rsi
void clear_relevant(std::vector<T>* vecp) { movq 8(%rdi), %rcx
for(unsigned i=0; i<vecp->size(); i++) { xorl %edx, %edx
vecp->at(i).relevant = 0; xorl %eax, %eax
} subq %rsi, %rcx
} sarq $4, %rcx
testq %rcx, %rcx
je .L1
.p2align 4,,10
.p2align 3
.L5:
void clear_relevant2(std::vector<T>* vecp) { salq $4, %rdx
std::vector<T>& vec = *vecp; addl $1, %eax
auto s = vec.size(); movl $0, 4(%rsi,%rdx)
for (unsigned i = 0; i < s; ++i) { movl %eax, %edx
vec[i].relevant = 0; cmpq %rcx, %rdx
} jb .L5
} .L1:
rep ret
.cfi_endproc
.cfi_startproc
movq 8(%rdi), %rdx
movq (%rdi), %rax
cmpq %rax, %rdx
je .L17
void clear_relevant3(std::vector<T>* vecp) { .p2align 4,,10
for (auto& p : *vecp) p.relevant = 0; .p2align 3
} .L21:
movl $0, 4(%rax)
addq $16, %rax
cmpq %rax, %rdx
jne .L21
.L17:
rep ret
.cfi_endproc
.cfi_startproc
movq 8(%rdi), %rdx
movq (%rdi), %rax
cmpq %rdx, %rax
void clear_relevant4(std::vector<T>* vecp) { je .L12
std::for_each(vecp->begin(), vecp->end(), .p2align 4,,10
[](T& o){o.relevant=0;}); .p2align 3
} .L16:
movl $0, 4(%rax)
addq $16, %rax
cmpq %rax, %rdx
jne .L16
.L12:
rep ret
.cfi_endproc