[c++] неинициализированные статические переменные
Если я правильно помню, aaa в зависимости от компилятора может оказаться как нулём, так и нет. А вот будет ли нулём bbb и всегда ли? Сам никаких упоминаний в стандарте, к сожалению, не нашёл.У тебя bbb только задекларировано, но не определено. Оно должно быть определено в некоторой одной единице компиляции, иначе будет ошибка линковки.
Если же ты определишь bbb без инициализации, то будет тоже самое, что с любыми другими глобальными переменными без инициализации, в частности для классов будет конструктор по умолчанию вызван.
А почему aaa должен быть нулём заполняться, я не понял: если обнуление не прописано в конструкторе, то зачем совершать лишнее действие, если лучше выдать хинт/варн?
upd:
9.4.2 Static data members
...
2 The declaration of a static data member in its class definition is not a definition and may be of an
incomplete type other than cv-qualified void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name
of the static data member shall be qualified by its class name using the :: operator. The initializer
expression in the definition of a static data member is in the scope of its class (3.3.6).
...
7 Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).
class A {
private:
A;
static A* a;
public:
A& instance {
if(!a) a = new A;
return a;
}
Сразу написать "static A* a = 0;" нельзя, компилятор пошлёт далеко и надолго.
Сейчас это реализуется как
class A {
private:
A;
public:
A& instance {
static A a;
return a;
}
Но хотелось бы понять, как это всё-таки сделать через переменную класса. Поскольку это хидер, вынести инициализацию переменной за пределы класса нельзя.
А почему aaa должен быть нулём заполняться, я не понял: если обнуление не прописано в конструкторе, то зачем совершать лишнее действие, если лучше выдать хинт/варн?Варн, естественно, выдаётся, тем не менее указатель в gcc по умолчанию вроде бы всё-таки равен нулю.
Сейчас это реализуется каки чем не устраивает? это рекомендуемое стандартное решение - когда static переменная класса заменяется на static переменную внутри метода.
Всем устраивает, просто стало интересно.
template<class _Sy>Для шаблонных классов стандарт разрешает определение статических членов в заголовке. Минимальный код, необходимый для делания класса A синглтоном следующий:
class Singleton
{
static std::auto_ptr<_Sy> instance;
Singleton(Singleton&) {}
protected:
Singleton {}
~Singleton {}
public:
static _Sy &GetInstance(void);
};
template<typename _Sy> std::auto_ptr<_Sy> Singleton<_Sy>::instance;
template<class _Sy>
_Sy &Singleton<_Sy>::GetInstance(void)
{
if (!instance.get
{
instance.reset(new _Sy;
}
return static_cast<_Sy&>(*instance);
}
class A : public Singleton<A>
{
private:
A {}
~A {}
friend class Singleton<A>;
friend class std::auto_ptr<A>;
};
И это все только чтобы не оставлять переменную экземпляра как локальную в функции?
Зато решение интересное, кстати.
Зато решение интересное, кстати.Ты даже не понимаешь, где определение, а где объявление, что ты можешь сказать об интересности решения?
Я к тому, что наворотить можно много чего «интересного», понимать бы зачем.
Если auto_ptr «потокобезопасен», то я солидарен с этим решением, но ты ведь не об этом подумал.
upd: да даже если дело в многопоточности, то InterlockedCompareExchange решает проблему, правда с переносимостью вылазит проблема.
В общем, , поясни, не догоняю.
Но мой код гораздо легче сделать потокобезопасным, собственно, изначально я написал именно такую версию (почти рабочую: позже выяснилось, что m$ нагло врёт в документации касательно слова volatile а затем уже удалил всё, что касается защиты от одновременного вызова из двух потоков.
upd: да даже если дело в многопоточности, то InterlockedCompareExchange решает проблему, правда с переносимостью вылазит проблема.Что-то не приходит в голову достаточно красивый и рабочий вариант решения проблемы. С критической секцией (а её обёртку в класс не сложно перенести) гораздо проще выходит.
Что-то не приходит в голову достаточно красивый и рабочий вариант решения проблемы. С критической секцией (а её обёртку в класс не сложно перенести) гораздо проще выходит.Критическая секция неоправданно медленнее.
m$ нагло врёт в документации касательно слова volatileПруфлинк.
Могу посоветовать прочитать мнение Андрея Александреску.
Критическая секция неоправданно медленнее.давай ты сперва напишешь свой вариант (используя статическую переменную я свой, а затем будем сравнивать
Да, согласен, твой код подходит как отправная точка для установления потоковой безопасности и в нем обошли проблему описания в заголовочном файле. В такой формулировке видна ценность этого кода.
давай ты сперва напишешь свой вариант (используя статическую переменную я свой, а затем будем сравниватьInterlockedCompareExchange против критической секции, а не против базового шаблона для синглтонов.
А, ещё в мсдн за 2008й год указано, что начиная с 2005й студии так делается.
Подумал, конструктор все равно синхронизировать придется, Interlocked* не поможет, придется критическую секцию делать.
вставляют aquire перед чтением и release после записи volatile-переменныхТам сказано про Acquire _semantics_ и Release _semantics_, в том же MSDN подробно разъяснено, что под этим имеется в виду. Никто не обещал поназаводить критических секций.
Acquire memory semantics specify that the memory operation being performed by the current thread will be visible before any other memory operations are attempted. Release memory semantics specify that the memory operation being performed by the current thread will be visible after all other memory operations have been completed.
ок, убедил: я недочитал мсдн. Впрочем, ошибки там всё равно попадаются, во всяком случае раньше были (в онлайн-версии пока не находил, т.к. редко ею пользуюсь, но в локальной версии за 2005й год пару раз натыкался на то, что опровергалось на практике).
aaa в зависимости от компилятора может оказаться как нулём, так и нет.не столько от компилятора, сколько от того, где этот класс размещен. Если на куче или в стеке, то скорее всего занулен не будет, если же рассматривать статический объект, то глупо было бы туда записывать по умолчанию не нули.
О многопоточности в данном случае речи не шло.
bss не зануляется под вендой?
А что я еще не понимаю? Расскажи, мне правда интересно.Кто ж тебя знает, что ты еще не понимаешь.
Вот из этого
О многопоточности в данном случае речи не шло.следует, что ты не понял, зачем написал такую хитрую реализацию. Хотя ты назвал ее "интересной". Если не брать в рассчет многопоточность, то называть ее "интересной" как минимум глупо. В случае заведомо однопоточного приложения (что в наши дни редкость, но все же есть еще ситуации, когда можно считать приложение однопоточным) это решение я бы назвал "избыточным".
Избыточное, да, я не спорю, и в моем случае вариант с локальной static переменной куда удобнее. Но что мешает его реализации при этом быть интересной? Не красивой, удобной или короткой, а просто интересной?
Во, вот об этом я не подумал. Вроде как bss зануляется всегда.
Во, вот об этом я не подумал. Вроде как bss зануляется всегда.Не всегда, а по умолчанию.
А как сделать не по умолчанию? C runtime подменить?
А как сделать не по умолчанию?Задать значение при описании, вестимо
// global scope:
int i = 7;
или
void whatever
{
static int j = 18;
...
}
Всё чудесно, только тогда это попадёт в data, а не в bss.
А хотя я спизднул. bss - это именно для нулевых. Читать не умею, видимо
Оставить комментарий
doublemother
Что говорит на их счёт стандарт?Если я правильно помню, aaa в зависимости от компилятора может оказаться как нулём, так и нет. А вот будет ли нулём bbb и всегда ли? Сам никаких упоминаний в стандарте, к сожалению, не нашёл.