Статическая и членская переменная - PullRequest
3 голосов
/ 09 марта 2009

Для отладки я хотел бы добавить некоторые переменные счетчика в мой класс. Но было бы неплохо сделать это без изменения заголовка, чтобы вызвать большую перекомпиляцию.

Если бы я правильно понял ключевое слово, следующие два фрагмента были бы совершенно идентичны. Предполагая, конечно, что есть только один экземпляр.

class FooA
{
public:
    FooA() : count(0) {}
    ~FooA() {}

    void update()
    {
        ++count;
    }

private:
    int count;
};

против

class FooB
{
public:
    FooB() {}
    ~FooB() {}

    void update()
    {
        static int count = 0;
        ++count;
    }
};

В FooA , счетчик может быть доступен в любом месте класса, а также раздувает заголовок, так как переменная должна быть удалена, когда больше не нужна.

В FooB переменная видна только внутри одной функции, в которой она существует. Легко удалить позже. Единственный недостаток, который я могу вспомнить, это то, что счет FooB распределяется между всеми экземплярами класса, но в моем случае это не проблема.

  • Это правильное использование ключевого слова? Я предполагаю, что как только count создается в FooB , он остается созданным и не повторно инициализируется для обнуления каждого вызова для обновления.
  • Есть ли какие-то другие предупреждения или хедсэпы, о которых мне следует знать?

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

Ответы [ 4 ]

3 голосов
/ 09 марта 2009

Ваши предположения о переменных статических функций верны. Если вы обращаетесь к этому из нескольких потоков, это может быть неправильно. Рассмотрите возможность использования InterlockedIncrement ().

2 голосов
/ 09 марта 2009

То, что вы действительно хотите, для вашего долгосрочного инструментария C ++ - это многопоточный, универсальный класс счетчиков отладки, который позволяет вам помещать его в любое место и использовать его, а также быть доступным из любого другого места для его печати. Если ваш код чувствителен к производительности, вы, вероятно, захотите, чтобы он автоматически ничего не делал в сборках без отладки.

Интерфейс для такого класса, вероятно, будет выглядеть так:

class Counters {
public:
  // Counters singleton request pattern.
  // Counters::get()["my-counter"]++;
  static Counters& get() {
    if (!_counters) _counters = new Counters();
  }

  // Bad idea if you want to deal with multithreaded things.
  // If you do, either provide an Increment(int inc_by); function instead of this,
  // or return some sort of atomic counter instead of an int.
  int& operator[](const string& key) {
    if (__DEBUG__) {
      return _counter_map.operator[](key);
    } else {
      return _bogus;
    }
  }

  // you have to deal with exposing iteration support.

private:
  Counters() {}

  // Kill copy and operator=
  void Counters(const Counters&);
  Counters& operator=(const Counters&);

  // Singleton member.
  static Counters* _counters;

  // Map to store the counters.
  std::map<string, int> _counter_map;

  // Bogus counter for opt builds.
  int _bogus;
};

Как только вы это получите, вы можете оставить его по своему желанию в любом месте .cpp файла, позвонив по телефону:

void Foo::update() {
  // Leave this in permanently, it will automatically get killed in OPT.
  Counters::get()["update-counter"]++;
}

И в вашем основном случае, если вы встроили поддержку итераций, вы делаете:

int main(...) {
  ...
  for (Counters::const_iterator i = Counters::get().begin(); i != Countes::get().end(); ++i) {
    cout << i.first << ": " << i.second;
  }
  ...
}

Создание класса counters довольно тяжело, но если вы делаете кучу кодов cpp, вам может быть полезно написать один раз, а затем просто связать его как часть любой библиотеки.

1 голос
/ 09 марта 2009

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

В файле FooC.cpp

namespace {
int count=0;
}

void FooC::update()
{
    ++count;
}
1 голос
/ 09 марта 2009

Основные проблемы со статическими переменными возникают, когда они используются вместе с многопоточностью. Если ваше приложение однопоточное, то, что вы делаете, совершенно правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...