我的理解是,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 显然更可取。这个语境我是完全同意和理解的。
我不清楚是否应该将相同的逻辑应用于更大的数据类型,例如数组或 vector 。我在代码中经常发现的一件事是这样的:
#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);
}
Note: Before you guys jump on this, I totally realize that you don't actually need a vector in this example. I am just making a stupid example so that the binary code is not too large on Godbolt.
此处不本地化数据(又名代码段 1)的基本原理是缓冲区可能是一些大 vector ,我们不想在每次调用函数时都重新分配它。
片段 2 的基本原理是更好地本地化数据。
那么对于这个场景我应该应用什么样的逻辑呢?我对您实际需要 vector 的情况感兴趣(在这种情况下您不需要)。
我应该遵循本地化逻辑吗?还是我应该遵循我应该尝试防止重复重新分配的逻辑?
我意识到在实际应用程序中,您需要对性能进行基准测试,而不是 Godbolt 中的编译大小。但我想知道这种情况下我的默认样式应该是什么(在我开始分析代码之前)。
最佳答案
您描述的场景中的主要考虑因素是:“缓冲区是 Bob 不可或缺的一部分吗?或者它只是我们在 bar()
的实现中使用的东西?”
如果每个 Bob 在其作为 Bob 的整个生命周期中都有一系列连续的字符,那么 - 那应该是一个成员变量。如果您只形成该序列来运行 bar()
,那么根据“最小相关范围”规则,该 vector 将仅作为局部变量存在于 bar()
中。
现在,以上是一般情况下的答案。有时,出于性能原因,您可能最终会破坏干净合理的抽象。例如:您可能分配了一些单个 vector ,并且仅将其与 Bob 关联了一段时间,然后将缓冲区与 Bob 分离,但将其保存在某个缓冲区缓存中。但除非你有充分的理由,否则不要考虑这些扭曲。
关于c++ - vector 可变范围的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58337914/