Почему использование статических переменных пространства имен / класса является плохой идеей в C ++? - PullRequest
2 голосов
/ 28 апреля 2011

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

namespace XXX
{
    static int i;
    class YYY
    {
        static m_i;     
    };
}

Использует ли статические переменные только в файле .cpp (поэтому они невидимы для другого кода) файл в порядке?

Ответы [ 5 ]

3 голосов
/ 28 апреля 2011

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

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

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

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


Также обратите внимание, что атомные переменные можно безопасно читать / записывать из различныхпотоки.Для простых счетчиков это часто хорошее решение: использование атомарного приращения.В C ++ 0x вы можете использовать «атомарный», предварительно используйте функцию ОС / компилятора, которая это делает.Как и в случае с одноэлементным шаблоном, вы можете легко спроектировать классы, в которых каждая функция синхронизируется, поэтому пользователю-одиночке не нужно об этом беспокоиться.Другими словами, статика не является поточно-ориентированной даже при написании.

2 голосов
/ 28 апреля 2011

Различные вещи, допускаемые C ++, представляют собой выбор и компромисс в дизайне программного обеспечения.Нет ничего изначально, абсолютно злого в любом из них (кроме, возможно, спецификаций броска, которые профессор Страустроп считает неисправным ;-P).

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

  • для всей программы будет использоваться только одна копия
    • может быть идеальным, например, вы хотите иметь модальное состояние для всей программы
    • ужасно: установка кода / использование значения может обнаружить, что другой код тем временем изменил его (это становится все более вероятным, поскольку программа становится больше и сложнее)
    • ужасно: в многопоточном коде вы должны использовать блокировку и /или атомарные операции, чтобы избежать повреждения данных и последующего ошибочного поведения и / или сбоев
  • , являющихся static:
    • другие единицы перевода не будут иметь доступа к этому
    • это не будет загрязнять таблицу символов, отображаемую хорошей IDE и т. Д.

Короче говоря, если вы понимаете, что пространства имен и static просто уменьшают конфликты идентификаторов, ониесть все другие плюсы / минусы, связанные с глобальными переменными ....

1 голос
/ 28 апреля 2011

Также у вас могут возникнуть проблемы со статическими членами класса при работе с общими библиотеками времени выполнения. Например: если у вас есть:

class A {
//...
static int staticInt;
//...
}; 

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

0 голосов
/ 28 апреля 2011

Один недостаток, о котором вы должны знать, это так называемое «фиаско статического порядка инициализации». Вот пример:

// foo.cpp

class foo {
  public:
    static bar m_bar;
};

bar foo::m_bar;

// baz.cpp

class baz {
  public:
    baz() { 
     /* some code */
     foo::m_bar.someMethod(); 
    }
};

baz g_baz; //TROUBLE!!

Стандарт C ++ не дает никаких гарантий относительно того, какие из них будут инициализированы первыми из m_bar и g_baz. Если вам повезет и m_bar будет инициализирован первым, g_baz будет создан без проблем. Если нет, то ваша программа, скорее всего, будет зависать или даже хуже.

Замена m_bar на метод, возвращающий статический указатель, созданный при первом использовании, позволяет обойти эту проблему (примечание: она по-прежнему не поточно-ориентирована):

class foo {
  public:
    static bar &getBar() { if(!m_barinst) m_barinst = new bar; return *m_barinst; }
  private:
    static bar *m_barinst;
};

bar *foo::m_barinst = NULL;
0 голосов
/ 28 апреля 2011

Во-первых, это не потокобезопасно. Возможно, вы захотите рассмотреть шаблон синглтона с некоторой блокировкой, чтобы защитить его.

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