带有向量的可变范围的最佳做法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有向量的可变范围的最佳做法相关的知识,希望对你有一定的参考价值。
我的理解是,C ++最佳实践是定义可能范围最小的变量。
我的理解是,这样做的主要原因是它将有助于防止意外重用。此外,这样做几乎不会对性能造成任何影响(或者有人告诉我)。相反,人们似乎表明,当在本地定义变量时,编译器实际上可能能够生成等效或更好的代码。例如,以下两个函数产生相同的二进制文件in Godbolt:
#include <cstdio>
#include <cstdlib>
void printRand1() {
char val;
for (size_t i = 0; i < 100 ; ++i) {
val = rand();
puts(&val);
}
}
void printRand2() {
for (size_t i = 0; i < 100 ; ++i) {
const char val = rand();
puts(&val);
}
}
因此,在这种情况下,显然最好使用版本2。我完全可以同意并理解这一背景。
我不清楚的是,是否应将相同的逻辑应用于较大的数据类型,例如数组或向量。我在代码中发现很多特别的东西是这样的:
#include <cstdio>
#include <cstdlib>
#include <vector>
struct Bob {
std::vector<char> buffer;
void bar(int N) {
buffer.resize(N);
for (auto & elem : buffer) {
elem = rand();
puts(&elem);
}
}
};
void bob() {
Bob obj;
obj.bar(100);
}
尽管在这个愚蠢的示例中我们可以更好地对数据进行本地化:
#include <cstdio>
#include <cstdlib>
#include <vector>
struct Bob {
void bar(int N) {
std::vector<char> buffer(N);
for (auto & elem : buffer) {
elem = rand();
puts(&elem);
}
}
};
void bob() {
Bob obj;
obj.bar(100);
}
注意:在你们开始之前,我完全意识到在这个例子中您实际上不需要向量。我只是在做一个愚蠢的示例,以使Godbolt上的二进制代码不会太大。
这里不对数据进行本地化的理由(也就是代码片段1)是缓冲区可能是一些大向量,并且我们不想每次调用函数时都继续分配它。
摘录2的基本原理是更好地定位数据。
那么,对于这种情况我应该采用什么逻辑?我对您实际上需要向量的情况感兴趣(在这种情况下您不需要)。
我应该遵循本地化逻辑吗?还是应该遵循应该避免重复分配的逻辑?
我意识到,在实际的应用程序中,您只需要基准性能,而不是Godbolt中的编译大小。但是我想知道在这种情况下我的默认样式应该是什么(在开始分析代码之前)。
您所描述的场景中的主要考虑因素是:“缓冲区是Bob的组成部分吗?或者它只是我们在实现bar()
时使用的东西?”
如果每个Bob在其一生中都有一系列连续的字符,那么-应该是成员变量。如果仅形成要运行bar()
的序列,则按照“最小相关范围”规则,该向量将仅作为局部变量存在于bar()
中。
现在,以上是一般情况的答案。有时,出于性能原因,您可能最终破坏了干净合理的抽象。例如:您可能分配了一个向量,并且仅将其与Bob关联了一段时间,然后从Bob分离了缓冲区,但将其保留在某些缓冲区缓存中。但是,除非您有充分的理由,否则请不要考虑这些扭曲。
在版本2中,将为每个bar()调用分配并释放内存。虽然版本一将重用已经分配的块。对于单次呼叫,没关系,对于多次呼叫,则首选版本1。
以上是关于带有向量的可变范围的最佳做法的主要内容,如果未能解决你的问题,请参考以下文章