Как запретить GCC генерировать охрану для статических членов - PullRequest
0 голосов
/ 08 октября 2019

Ниже приведен минимальный пример, который иногда генерирует охранников, а иногда нет:

struct A {
    inline A(int v = 0) {} // without ctors, guards are omitted
    int m1() const {
        return m;
    }
private:
    int m = 0;
};

//namespace { // without anon-ns guards are generated 
    template<typename T>
    struct X {
        static int foo() {
            // static T m; // even as local-static and -fno-threadsafe-statics, guards are generated 
            return m.m1();
        }
        inline static T m; // comment this and uncomment above to try as local-static
    };
//}

int main() {
    return X<A>::foo();    
}

Подводя итог:

  • без ctor в классе A, охранники никогда не генерируются
  • использование anaon-ns также предотвращает охрану
  • делает статический член m статическим локальным в foo() по-прежнему генерирует защиту (с -fno-threadsafe-statics) (закомментируйте / раскомментируйте соответствующие строки в примере выше)

Итак, как предотвратить создание охранников в случае, если у класса A есть ctor и использование anon-ns невозможно?

Ответы [ 3 ]

0 голосов
/ 09 октября 2019

Ключевой особенностью для подавления защиты являются constinit и constexpr ctors:

#include <cstdint>

struct A {
    inline constexpr A(uint8_t v) : m{v} {} // without constexpr it should not compile, but does anymay
    auto m1() const {
        return m;
    }
private:
     uint8_t m{0};
};

template<typename T>
struct X {
    static auto foo() {
        return m.m1();
    }
    constinit inline static T m{2}; // requires constexpr ctor
};
int main() {
    return X<A>::foo();    
}

При constinit инициализация должна выполняться во время компиляции, поэтому нет необходимости генерировать охрану. Для этого требуется constexpr ктор. В приведенном выше примере ctor (по крайней мере, для gcc) может быть объявлен без constexpr, но это может быть ожидающая ошибка.

0 голосов
/ 09 октября 2019

inline переменные инициализируются каждой единицей перевода, которая включает ее определение. Без этой защиты каждая единица трансляции будет повторно инициализировать одну и ту же переменную.

constexpr конструкторы, очевидно, делают инициализацию статической , так что она не требует инициализации во время выполнения,Но для объектов, которые используют динамическую инициализацию, требуется защита.

0 голосов
/ 08 октября 2019

Вы можете объявить конструктор A как constexpr, чтобы статически инициализировать X<A>::m.

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

в Itanium C ++ ABI :

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

...