Статическая инициализация локальных переменных
От: Alexander Pazdnikov  
Дата: 01.11.11 07:25
Оценка:
Здравствуйте, Уважаемые коллеги.

Гарантирует ли стандарт, что инициализация локальной статической переменной будет выполнена при первом входе в тело функции, даже если вызов функции выполняется до вызова функции main

Ссылки по теме со ссылкой на стандарт
Автор: Mr. None
Дата: 05.11.04
и здесь
Автор: rg45
Дата: 21.03.06
.

Ниже привожу пример кода.

1. Меня коллеги убеждают, что локальные статические переменные инициализируются вместе с глобальными статическими переменными и такой код для однопоточных приложений некорректен.
2. Чтобы сделать его корректным, можно воспользоваться потокобезопасным сингелтоном с созданием объекта в куче, можно ли сделать потокобезопасную инициализацию на static переменных?


#include <string>                                                                                                                                                                                                                            
#include <iostream>                                                                                                                                                                                                                          
                                                                                                                                                                                                                                             
using namespace std;                                                                                                                                                                                                                         
                                                                                                                                                                                                                                             
string& get_A()                                                                                                                                                                                                                              
{                                                                                                                                                                                                                                            
    static string a("Hello world!");                                                                                                                                                                                                         
    return a;                                                                                                                                                                                                                                
}                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                             
struct B                                                                                                                                                                                                                                     
{                                                                                                                                                                                                                                            
    B() : m_a(get_A()) { cout << m_a << endl; }                                                                                                                                                                                              
    string &m_a;                                                                                                                                                                                                                             
};                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                             
static B global_B;                                                                                                                                                                                                                          
                                                                                                                                                                                                                                             
int main()                                                                                                                                                                                                                                   
{                                                                                                                                                                                                                                            
    return 0;                                                                                                                                                                                                                                
}
static инициализация локальных переменных
Re: Статическая инициализация локальных переменных
От: uzhas Ниоткуда  
Дата: 01.11.11 07:45
Оценка: 2 (1)
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP> Здравствуйте, Уважаемые коллеги.


AP>Гарантирует ли стандарт, что инициализация локальной статической переменной будет выполнена при первом входе в тело функции, даже если вызов функции выполняется до вызова функции main

ссылка по теме: http://stackoverflow.com/questions/55510/when-do-function-level-static-variables-get-allocated-initialized

AP>Ниже привожу пример кода.


AP>1. Меня коллеги убеждают, что локальные статические переменные инициализируются вместе с глобальными статическими переменными и такой код для однопоточных приложений некорректен.

инициализируются в рантайме при выполнении строчки static type var = f();

AP>2. Чтобы сделать его корректным, можно воспользоваться потокобезопасным сингелтоном с созданием объекта в куче, можно ли сделать потокобезопасную инициализацию на static переменных?

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

6.7 Declaration statement [stmt.dcl]
4. The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage
duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a
block-scope entity with static storage duration, if applicable, is performed before its block is first entered.
An implementation is permitted to perform early initialization of other block-scope variables with static or
thread storage duration under the same conditions that an implementation is permitted to statically initialize
a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is
initialized the first time control passes through its declaration; such a variable is considered initialized upon
the completion of its initialization. If the initialization exits by throwing an exception, the initialization
is not complete, so it will be tried again the next time control enters the declaration. If control enters
the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for
completion of the initialization.
88 If control re-enters the declaration recursively while the variable is being
initialized, the behavior is undefined. [ Example:
int foo(int i) {
static int s = foo(2*i); // recursive call — undefined
return i+1;
}
—end example ]

88) The implementation must not introduce any deadlock around execution of the initializer.

Re: Статическая инициализация локальных переменных
От: Erop Россия  
Дата: 01.11.11 09:41
Оценка: +1 -1
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>1. Меня коллеги убеждают, что локальные статические переменные инициализируются вместе с глобальными статическими переменными и такой код для однопоточных приложений некорректен.


Вообще говоря некорректен, но беда там в другом месте сидит. К этой переменной могут обратиться уже после того, как она разрушится.

Сделать корректно тоже можно.
Например так:
string& get_A1(){
    static char buffer[sizeof(std::string)];
    static string& a = *::new(buffer) std::string( "Hello world!" );
    return a;
}


Правда при этом мы, возможно, будем при отгрузке приложения терять потроха строчки, ну да обычно это не страшно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Статическая инициализация локальных переменных
От: Alexander Pazdnikov  
Дата: 01.11.11 10:37
Оценка:
Здравствуйте, Erop, Вы писали:

E>Вообще говоря некорректен, но беда там в другом месте сидит. К этой переменной могут обратиться уже после того, как она разрушится.


Вообщем случае, кроме shared_ptr больше альтернатив нет, чтобы гарантировано безопасно разрушить объект?

E>Сделать корректно тоже можно.

E>Например так:
E>string& get_A1(){
E>    static char buffer[sizeof(std::string)];
E>    static string& a = *::new(buffer) std::string( "Hello world!" );
E>    return a;
E>}              
E>


Инициализация локальных статических переменных обязательна в порядке их объявления?
Re[3]: Статическая инициализация локальных переменных
От: Erop Россия  
Дата: 01.11.11 11:37
Оценка: 2 (1) -1
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Вообщем случае, кроме shared_ptr больше альтернатив нет, чтобы гарантировано безопасно разрушить объект?

Не понимаю вообще о чём ты толкуешь.

В схеме с синглетоном shared_ptr вообще никаких проблем не решает и НЕ НУЖЕН!


Вот смотри:

std::string& get()
{
    static std::string seed;
    return seed;
}

static class first {
public: 
    ~first() { get() += "~first(); "; }  // Упс, как тут поможет shared_ptr? ;)
} f;

static class second {
public:
    second() { get += "second(); "; }
} s;



Чего будет-то?
1) создадут f
2) создадут s
3) из конструктора s создадут seed
4) выполнят main()
5) начнут разрушать, в порядке обратном порядку создания
5.1) разрушат seed
5.2) разрушат s
5.3) разрушат f
5.3.1) из деструктора f получат снова доступ к месту, где лежал уже разрушенный seed и тут случиться УПС

пример можно и упростить до:
static struct UPS {
    UPS() { get() += "UPS(); "; }
    ~UPS() { get() += "~UPS(); "; }
} ups;


AP>Инициализация локальных статических переменных обязательна в порядке их объявления?


Это я не понял. Они инициализирутся в момент, когда поток управления впервые достигает оператора их объявления...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Статическая инициализация локальных переменных
От: Masterkent  
Дата: 01.11.11 12:36
Оценка: :)
Alexander Pazdnikov:

AP>1. Меня коллеги убеждают, что локальные статические переменные инициализируются вместе с глобальными статическими переменными и такой код для однопоточных приложений некорректен.


Не вижу в данном коде ничего некорректного. И, кстати, если добавить в B пользовательский деструктор, то из этого деструктора можно будет вызывать функцию get_A(), т.к. пока он полностью не отработает, локальный объект a уничтожаться не будет — см. 3.6.3/1:

If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first.

Re[2]: Статическая инициализация локальных переменных
От: Erop Россия  
Дата: 01.11.11 12:55
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>Не вижу в данном коде ничего некорректного.

Плохо...

Кстати, с чем ты не согласен?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Статическая инициализация локальных переменных
От: Кодт Россия  
Дата: 02.11.11 09:47
Оценка:
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Вообщем случае, кроме shared_ptr больше альтернатив нет, чтобы гарантировано безопасно разрушить объект?


Даже с shared_ptr нет гарантии того, что произойдёт запутывание порядка разрушения объектов.
Только вместо разрушенного объекта мы попробуем обратиться к разрушенному (и, кстати, не обнулённому, потому что какой смысл обнулять при разрушении) умному указателю.

У Александреску в "Современном С++" синглетонам с разными политиками живучести посвящено много текста. И нельзя сказать, что там все проблемы решены.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.