Сколько экземпляров статических данных, объявленных внутри статической функции-члена в заголовочном файле? - PullRequest
1 голос
/ 01 февраля 2011

Я работаю над компиляцией Cppcheck в AIX с использованием xlC.Каждый класс контролера является производным от класса Check, конструктор которого отвечает за регистрацию этого типа контролера в глобальном статическом списке.

Вот соответствующая часть рассматриваемого кода (имена файлов ссылаются на полный исходный код наGithub):

check.h

class Check {
public:
    Check() {
        instances().push_back(this);
        instances().sort();
    }
    static std::list<Check *> &instances() {
        static std::list<Check *> _instances;
        return _instances;
    }
    // ...
};

checkbufferoverrun.h

class CheckBufferOverrun: public Check {
    // ...
};

checkbufferoverrunr.cpp

// Register this check class (by creating a static instance of it)
namespace
{
CheckBufferOverrun instance;
}

Обратите внимание, как объявлена ​​статическая переменная _instances внутри функции static в файле header (соответствующего файла check.cpp нет).При компиляции с g++ компилятор и компоновщик работают вместе, обеспечивая единственную реализацию статической функции instances() и, следовательно, только один экземпляр статического списка _instances.Все различные классы проверки, созданные в разных файлах .cpp, регистрируются в одном и том же списке _instances вместе.

Однако, в xlC AIX этот же код в конечном итоге создает разные instances() функция для каждого .cpp файла, в который он включен, каждый из которых имеет свой статический список _instances.Таким образом, больше нет единого центрального _instances списка, который заставляет Cppcheck не выполнять большинство своих проверок.

Какой компилятор в этом случае корректен?

Обновление : Этот вопрос не о том, как исправить проблему, я уже сделал это.Мне интересно, какое поведение правильно .

Ответы [ 3 ]

9 голосов
/ 01 февраля 2011

g ++ имеет правильное поведение: должен быть ровно один экземпляр объекта. Стандарт C ++ гласит (C ++ 03 7.1.2 / 4):

Статическая локальная переменная во внешней встроенной функции всегда ссылается на один и тот же объект.

Поскольку у класса есть внешняя связь, функция статического члена также имеет внешнюю связь, согласно C ++ 03 3.5 / 5:

функция-член ... имеет внешнюю связь, если имя класса имеет внешнюю связь.

Поскольку функция-член определена в определении класса, это встроенная функция, согласно C ++ 03 7.1.2 / 3:

Функция, определенная в определении класса, является встроенной функцией.

2 голосов
/ 01 февраля 2011

В данном конкретном случае g ++ верен (при условии, что статическая функция-член instances() возвращает ссылку, то есть опечатка, верно?).Возможно, вы захотите переместить определение функции instances() в файл cpp, что должно быть решением в xlc.

1 голос
/ 01 февраля 2011

Исправьте это до:

   static std::list<Check *>& instances();

// check.cpp
 std::list<Check *> & Check::instances()
 {
     static std::list<Check *> _instances;
     return _instances;
 }

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

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

Для полностью поточно-ориентированного способа конструирования синглетонов или неатомных статик вы можете использовать boost :: Once.

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