2009-03-09 5 views
3

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

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

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, он остается созданным и не переинициализирован до нуля для каждого вызова для обновления.
  • Есть ли какие-либо другие оговорки или головной убор, о которых я должен знать?

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

ответ

3

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

1

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

1

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

В файле FooC.cpp

namespace { 
int count=0; 
} 

void FooC::update() 
{ 
    ++count; 
} 
+0

Почему вы добавляете его в пространство имен? И можете ли вы действительно добавить/удалить его по своему усмотрению? Если я удалю определение пространства имен там, не будет ли подсчет ++; ошибка причины строки? – Mizipzor

2

То, что вы действительно хотите, для долгосрочной 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; 
    } 
    ... 
} 

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