c++ - vector 可变范围的最佳实践

标签 c++ c++14

我的理解是,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/

相关文章:

c++ - 测试目录中的另一个 main.cpp

c++ - Win32下堆损坏;如何定位?

C++ 全局访问类属性时应该使用哪种设计模式

c++ - C++ 模板声明中的范围和默认参数 : Clarifying Standardese

c++ - 使用 STL 对两个数组进行条件迭代

c++ - C++ 中的单例习语

c++ - 对于具有抛出复制构造函数和 noexcept 按值复制赋值的类,is_nothrow_copy_assignable 的值是多少?

c++ - 我如何使用比系统提供的更新版本的 clang 链接到线程清理器?

c++ - 为什么我的用于删除重复字符的 c++14 程序在输出中给出了额外的字符?

c++ - 当我从我的继承列表中选择一个特定的隐藏函数时,我如何使用 noexcept?