Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь
Здравствуйте, Станислав Артемкин, Вы писали:
СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь
СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.
СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь
СА>Кое какая информация есть здесь: СА>http://www.codeproject.com/useritems/VC2003MeyersSingletonBug.asp
Очень странный баг. Как уже замечал ПК в топике, указанном выше, очень многое из std просто не работало бы в этом случае.
Я проверил на 6-ке и 7.1 (на остальных просто лениво проверять) — все нормально. Мысли?
Т.е. все ОК, как и ожидалось. Сформировалась никому не нужная Foo::GetInstance (которую затем выкинет линкер), и один глобальный объект класса Foo, который инициализируется как статический объект (видимо, потому что не имеет конструкторов, которые бы имели видимые последствия). Может, пример должен быть несколько сложнее?
СА>Исправлял уже 2 раза в нашем проекте.
СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь
Действительно странно. А в какой конкретно момент падает? При первом обращении, при выходе из программы или еще где-то? Если при выходе из программы, то это может быть связано с неопределенным порядком деинициализации статических объектов в C++. При переносе в cpp этот порядок вполне может поменяться.
Здравствуйте, Станислав Артемкин, Вы писали:
СА>Чтобы исправить надо перенести имплементацию метода GetInstance() в cpp-шник. Чтобы понять почему падает, добавьте счетчик созданных объектов в Foo и подивитесь
СА>Кое какая информация есть здесь: СА>http://www.codeproject.com/useritems/VC2003MeyersSingletonBug.asp
Типа использует разный флажок для выяснения того, что объект уже создали?
В описании бага пишут, что помогает шаблон класса. Интеренсо почему...
А такая конструкция помогает?
class Foo
{
public:
static Foo& GetInstance()
{
static Foo* p = 0;
if( p == 0 ) {
static Foo instance;
p = &instance;
}
return *p;
}
};
Кстати, такой ещё вопрос небанальный, а это случаем не воссоздание синглетона после его разрушения происходит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Andrew S, Вы писали:
AS>Очень странный баг. Как уже замечал ПК в топике, указанном выше, очень многое из std просто не работало бы в этом случае.
Здравствуйте, Станислав Артемкин, Вы писали:
СА>Всем привет, СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.
......
У меня абсолютно такая же проблема. Никакого multithreading. Баги лезли из разных мест, пока не заметил, что c'tor и d'tor вызываются по неск. раз.
Спасло перемещение реализации в CPP.
MS VC SP1 (v7.1.6030).
да, я тоже юзал эту реализацию (брал один в один с Эккеля), правда компилер g++, — тоже были баги
взял реализацию из БЧ — проблемы вроде исчезли (приложение кстати multithreading).
Здравствуйте, Станислав Артемкин, Вы писали:
СА>Всем привет,
СА>Возможно будет полезно. Следующая имплементация падает в релизной версии, скомпилированной MSVC++. Это дефект оптимизатора MSVC++.
СА>
На мой взгляд — ничего удивительного не происходит. Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))
Здравствуйте, Sergipu, Вы писали:
S>На мой взгляд — ничего удивительного не происходит.
Кому как
S>Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))
7.1.2/4
...
An inline function with external linkage shall have the same address in all translation units. A static
local variable in an extern inline function always refers to the same object. A string literal in an
extern inline function is the same object in different translation units.
S>На мой взгляд — ничего удивительного не происходит. Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))
Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.
Здравствуйте, Andrew S, Вы писали:
AS>Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.
Может быть стоит ключик оптимизации "передполагать, что нет двух ссылок на одну переменную"?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
AS>>Ну вот я привел код — инлайнится, но экземпляр — один. По поводу "соответствия" уже сказали, но указанное поведение и не воспроизводится. Может, дело в настройках? Хорошо бы настройки компилера и линкера, или просто проект, который это дело явно воспроизводит.
E>Может быть стоит ключик оптимизации "передполагать, что нет двух ссылок на одну переменную"?
Вот ключи:
cl /EHsc /GX /O2 /Op /FAs /FD /D "WIN32" /D "_CONSOLE" /c
link kernel32.lib user32.lib /subsystem:console /incremental:no /release
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Sergipu, Вы писали:
S>>На мой взгляд — ничего удивительного не происходит. B>Кому как
S>>Статическая ф-я GetInstance() инлайнится в 2 модуля компиляции вместе со своей статической переменной. 2 разные переменные — разные и значения. Другое дело, насколько такое поведение комилятора соответсвует стандарту... Мне кажется, что вполне, но если кто-то докажет обратное — буду благодарен за ценную инфу. )))
B>
B>7.1.2/4
B>...
B>An inline function with external linkage shall have the same address in all translation units. A static
B>local variable in an extern inline function always refers to the same object. A string literal in an
B>extern inline function is the same object in different translation units.
А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage?
Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией?
А>Изменится что-нибудь если GetInstance() будет в неймспейсе static inline функцией?
Да, тогда каждый объект будет уникальным
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage?
Да.
3.5/4
A name having namespace scope has external linkage if it is the name of
...
— a named class (clause 9), or an unnamed class defined in a typedef declaration in which the class has the
typedef name for linkage purposes (7.1.3); or
...
3.5/5
In addition, a member function, static data member, class or enumeration of class scope has external linkage
if the name of the class has external linkage.
А>Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией?
Да, в этом случае GetInstance будет internal, т.е. в каждой единице трансляции у этой функции будет своя копия статического объекта:
3.5/3
A name having namespace scope (3.3.5) has internal linkage if it is the name of
— an object, reference, function or function template that is explicitly declared static or,
...
Любите книгу — источник знаний (с) М.Горький
Re[5]: Креш в синглтоне Мейерса
От:
Аноним
Дата:
27.11.07 12:28
Оценка:
Здравствуйте, Bell, Вы писали:
А>>А можно заодно объяснить почему Foo::GetInstance() имеет external linkage? Потому что класс Foo имеет external linkage? B>Да.
[]
А>>Изменится что-нибудь если GetInstance() будет свободной глобальной или в неймспейсе static inline функцией? B>Да, в этом случае GetInstance будет internal, т.е. в каждой единице трансляции у этой функции будет своя копия статического объекта:
[]
Спасибо. А если GetInstance будет internal, то её адрес и сам код тоже, как и её статические данные, будут свои для каждой единицы трансляции? То есть полный копи/паст? Или это уже от компилятора зависит?
Здравствуйте, Аноним, Вы писали:
А>Спасибо. А если GetInstance будет internal, то её адрес и сам код тоже, как и её статические данные, будут свои для каждой единицы трансляции?
Да.
А>То есть полный копи/паст? Или это уже от компилятора зависит?
Полный копи/паст.
Любите книгу — источник знаний (с) М.Горький
Re[7]: Креш в синглтоне Мейерса
От:
Аноним
Дата:
27.11.07 13:19
Оценка:
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Аноним, Вы писали:
А>>Спасибо. А если GetInstance будет internal, то её адрес и сам код тоже, как и её статические данные, будут свои для каждой единицы трансляции? B>Да.
А>>То есть полный копи/паст? Или это уже от компилятора зависит? B>Полный копи/паст.
Спасибо за ликбез
Если Вам не надоели мои вопросы, то вот ещё
Для чего, в принципе, нужен internal linkage?
Для чего может понадобиться в каждом модуле дублировать код функций и константы?
Может это вынужденная мера языка, например, для поддержки шаблонов?
Здравствуйте, Аноним, Вы писали:
А>Для чего может понадобиться в каждом модуле дублировать код функций и константы? А>Может это вынужденная мера языка, например, для поддержки шаблонов?
1) internal l. в С++ лучше достигается не при помощи статических констант и функций, а при помощи анонимных пространств имён.
2) Ну вот представь себе, что написал ты что-то типа:
но с external l. и в другом каком-то cpp напишешь другую табличку. Будет геморр и путанница какая табличка к кому относится.
А при internal l. всё изолировано и хорошо выходит...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>Для чего, в принципе, нужен internal linkage?
Для изоляции некоей сущности в единице трансляции. А>Для чего может понадобиться в каждом модуле дублировать код функций и константы?
Главная фишка в том, что под одним и тем же именем в разных единицах трансляции могут скрываться разные сущности . Например разные функции с одинаковым именем.
А вот копия константы — это совсем даже не плохо — можно вставить ее прямо в исполняемый код и забыть о ссылках не нее.
А>Может это вынужденная мера языка, например, для поддержки шаблонов?
Скорее наоборот. В качетсве параметров шаблонов могут использоваться только сущности с external linkage. А статические функции и константы в текущем стандарте помечены как устаревшие:
7.3.1.1/2
The use of the static keyword is deprecated when declaring objects in a namespace scope (see annex D);
the unnamed-namespace provides a superior alternative.
Т.е. для этой цели рекомедуется использовать безымянные пространства имен:
namespace
{
void func() {};
}
В этом случае и имя изолировано, а значит не мешает другим идиницам трансляции, и функция func имеет внешнее связывание.
Любите книгу — источник знаний (с) М.Горький
Re[9]: Креш в синглтоне Мейерса
От:
Аноним
Дата:
27.11.07 14:38
Оценка:
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Аноним, Вы писали:
А>>Для чего может понадобиться в каждом модуле дублировать код функций и константы? А>>Может это вынужденная мера языка, например, для поддержки шаблонов?
E>1) internal l. в С++ лучше достигается не при помощи статических констант и функций, а при помощи анонимных пространств имён. E>2) Ну вот представь себе, что написал ты что-то типа:
E>но с external l. и в другом каком-то cpp напишешь другую табличку. Будет геморр и путанница какая табличка к кому относится.
E>А при internal l. всё изолировано и хорошо выходит...
Ага, полезная штука, спасибо.
Re[9]: Креш в синглтоне Мейерса
От:
Аноним
Дата:
27.11.07 14:59
Оценка:
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Аноним, Вы писали:
А>>Для чего, в принципе, нужен internal linkage? B>Для изоляции некоей сущности в единице трансляции. А>>Для чего может понадобиться в каждом модуле дублировать код функций и константы? B>Главная фишка в том, что под одним и тем же именем в разных единицах трансляции могут скрываться разные сущности . Например разные функции с одинаковым именем. B>А вот копия константы — это совсем даже не плохо — можно вставить ее прямо в исполняемый код и забыть о ссылках не нее.
А>>Может это вынужденная мера языка, например, для поддержки шаблонов? B>Скорее наоборот. В качетсве параметров шаблонов могут использоваться только сущности с external linkage. А статические функции и константы в текущем стандарте помечены как устаревшие: B>
B>7.3.1.1/2
B>The use of the static keyword is deprecated when declaring objects in a namespace scope (see annex D);
B>the unnamed-namespace provides a superior alternative.
B>Т.е. для этой цели рекомедуется использовать безымянные пространства имен: B>
B>namespace
B>{
B> void func() {};
B>}
B>
B>В этом случае и имя изолировано, а значит не мешает другим идиницам трансляции, и функция func имеет внешнее связывание.