Лучшие практики для переменных областей с векторами - PullRequest
0 голосов
/ 11 октября 2019

Насколько я понимаю, в C ++ рекомендуется определять переменные с наименьшей возможной областью действия.

Насколько я понимаю, основная причина этого заключается в том, что это поможет предотвратить случайное повторное использование. Кроме того, за это почти никогда не случается снижение производительности (или мне так сказали). Напротив, люди, кажется, указывают, что компилятор может фактически производить эквивалентный или лучший код, когда переменные определяются локально. Например, следующие две функции производят одинаковые двоичные файлы в 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), состоит в том, что буфер может быть каким-то большим вектором, и мы не хотим перераспределять его каждый раз, когда вызываем функцию.

Обоснованием для Snippet 2 является лучшая локализация данных.

Так какую логику я должен применить для этого сценария? Меня интересует случай, когда вам на самом деле нужен вектор (в данном случае вам это не нужно).

Должен ли я следовать логике локализации? или я должен следовать логике, что я должен попытаться предотвратить повторные перераспределения?

Я понимаю, что в реальном приложении вы бы хотели оценить производительность, а не скомпилированный размер в Godbolt. Но мне интересно, каким должен быть мой стиль по умолчанию для этого сценария (до того, как я начну профилировать код).

Ответы [ 2 ]

2 голосов
/ 11 октября 2019

Основное соображение в описываемом вами сценарии: «Является ли буфер неотъемлемой частью того, чем является Боб? Или это просто то, что мы используем при реализации bar()

Если каждыйУ Боба есть последовательность смежных символов на протяжении всей его жизни в качестве Боба, поэтому - это должна быть переменная-член. Если вы формируете эту последовательность только для запуска bar(), то по правилу «наименьшей релевантной области» этот вектор будет существовать только как локальная переменная внутри bar().


Теперь вышеприведенноеобщий ответ. Иногда по соображениям производительности вы можете нарушить чистые и разумные абстракции. Например: Вы можете выделить какой-то один вектор и связать его с Бобом на определенный период времени, затем отделить буфер от вашего Боба, но сохранить его в некотором буферном кеше. Но не думайте об этих видах искажений, если у вас нет веских причин для этого.

1 голос
/ 11 октября 2019

В версии 2 память будет выделяться и освобождаться при каждом вызове bar (). Пока первая версия будет использовать уже выделенный кусок. Для одного звонка это не имеет значения, для нескольких - предпочтительна версия 1.

...