Объекты против Статические переменные для сохранения состояния функции

#c #object #static

Вопрос:

У меня есть функция, которая обрабатывает данные, поступающие в виде последовательности. Из-за этого мне нужно знать значение определенных переменных из последнего вызова функции во время текущего вызова функции.

Мой текущий подход к этому заключается в использовании статических переменных. Моя функция выглядит примерно так:

 bool processData(Object message){
    static int lastVar1 = -1;

    int curVar1 = message.var1;
    if (curVar1 > lastVar1){
        // Do something
    }

    lastVar1 = curVar1;
}
 

Это всего лишь небольшой образец кода; на самом деле у меня есть более 10 статических переменных, отслеживающих разные вещи. Моя интуиция подсказывает мне, что использовать так много статических переменных, вероятно, не очень хорошая идея, хотя мне нечего подкреплять это чувство.

Мой вопрос: Есть ли лучший способ сделать это?

Альтернативой, которую я рассматривал, является использование объекта, полями которого являются lastVar1, lastVar2 и т. Д. Однако я не уверен, что хранение объекта в памяти будет более эффективным, чем использование статических переменных.

Комментарии:

1. вам не нужен объект с вызываемыми членами lastVar1 и т. lastVar2 Д. в дополнение к текущему объекту. Вам нужен класс с членами Var1 и т. Var2 Д. И двумя объектами current , previous и, если методу нужны оба, вызывающий должен передать их оба, вместо того, чтобы скрывать это внутри функции, делая ее в основном непроверяемой

2. объект с членом было бы проще протестировать и позволяло бы вызывать метод из нескольких контекстов (проблема реентелизма со статикой, …).

3. Статическая локальная переменная делает функцию нереентерабельной, что может иметь значение, если вы хотите запустить код в нескольких потоках.

4. Эта функция должна быть методом класса, а метод класса должен иметь закрытый член класса, который используется для этой цели. В конце концов, это то, для чего предназначен C : классы.

5. Изменяемое статическое состояние почти никогда не является правильным ответом; это довольно часто опора для поддержки дизайна, но, как ни странно, это часто его калечит. static состояние может затруднить модульное тестирование, так как состояние может передаваться между тестами, затруднить создание нескольких экземпляров (поскольку теперь они неявно разделяют состояние), не повторяется и т. Д. Вам лучше использовать структурированный дизайн, который просто записывает состояние previous и current -если не для вашего собственного здравомыслия, то, по крайней мере, для здравомыслия любого будущего сопровождающего

Ответ №1:

Ваш вопрос имеет привкус чисто стиля и мнений, хотя есть аспекты, которые не являются вопросом мнения: многопоточность и тестирование.

Подумайте об этом:

 bool foo(int x) {
    static last_val = -1;
    bool result = (x == last_val);
    last_val = x;
    return resu<
}
 

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

    foo(1);
   assert( foo(1) );    // silenty assumes that the last call did the right thing
 

Чтобы настроить предварительные условия для теста (первая строка), вам уже нужно предположить, что foo(1) это правильно, что каким-то образом противоречит цели тестирования этого вызова во второй строке.

Если методам нужен текущий объект и предыдущий объект, просто передайте оба:

 bool processData(const Objectamp; message,const Objectamp; previous_message){

    if (message.var1 > previous_message.var1){
        // Do something
        return true;
    }   
    return false;
}
 

Конечно, это просто переносит проблему отслеживания предыдущего сообщения на вызывающего абонента, хотя это прямолинейно и не требует возни со статикой:

  Object message, old_message;
 while ( get_more( message )) {
     processData(message, old_message);
     old_message = message;
 }
 

Комментарии:

1. К сожалению, я, возможно, слишком упростил свой код. Причина, по которой я просто не передаю old_message, заключается в том, что для получения значения curVar1 и других требуется выполнить нетривиальный объем обработки. Эту обработку пришлось бы выполнить дважды, если бы я должен был передать old_message

2. @Star-lordX нет, вам не нужно делать это дважды, вы делаете это один раз и дважды передаете методу. Ответ меняется лишь незначительно, подпись будет bool processData(Object message, Preprocessed current, Preprocessed previous)