2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Конструкторы глобалов в C++
Сообщение13.01.2019, 04:16 


06/04/18
220
Рассмотрим классическую задачу, часто встречающуюся на олимпиадах и собеседованиях: напишите Hello, world!, чтобы телом функции main были пустые фигурные скобки: {}
Классическое решение этой задачи судя по всему содержит ошибку:
Используется синтаксис C++
#include<iostream>

class hello {
    public:
        hello(){ std::cout << "Hello, world!\n"; }
} put;

int main(){
}
Ankit Asthana и Ayman Shoukry сообщают:
Цитата:
И дальше о том, что поскольку глобалы могут быть использованы в других единицах трансляции, компилятор не может их выкинуть за ненадобностью; эта обязанность возлагается на компоновщик. Ankit Asthana и Ayman Shoukry — это два программиста, принимавшие непосредственное участие в разработке Visual Studio. К тому же первый является автором многочисленных пособий по C++.

В стандарте языка говорится следующее:
Цитата:
3.7.1
If a variable with static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8

Если переменная со статическим классом памяти имеет инициализацию или деструктор с побочными эффектами, она не должна исключаться при оптимизации, даже если она выглядит как неиспользуемая, за исключением того, что классовый объект или его копия или результат перемещения может быть исключен, как указано в 12.8.
Конструктор с инструкцией вывода текста, очевидно, имеет побочный эффект. Вопрос в том, когда он будет вызван.
Цитата:
Должна ли динамическая инициализация нелокальной переменной со статическим классом памяти быть произведена перед первым оператором функции main, определяется реализацией. Если инициализация отложена на некоторый момент времени после выполнения первого оператора функции main, она должна произойти перед первым оdr-использованием (3.2) любой функции или переменной, описанной в той же единице трансляции как переменная, подлежащая инициализации.

Нелокальная переменная со статическим классом памяти инициализируемая с побочными эффектами, должна быть инициализирована, даже если она не оdr-используется (3.2, 3.7.1).
Вызов конструктора — это динамическая инициализация переменной классового типа. Вроде бы реализация имеет право отложить вызов этой функции до первого использования любой другой функции или переменной. Но у нас тело функции main — пустые скобки. В приведенном коде нет каких-то других функций или переменных. Может ли получиться так, что никакой инициализации в данном случае вообще не произойдёт?

 Профиль  
                  
 
 Re: Конструкторы глобалов в C++
Сообщение13.01.2019, 11:31 
Аватара пользователя


14/11/12
1255
Россия, Нижний Новгород
Компилируйте с опцией -O0

 Профиль  
                  
 
 Re: Конструкторы глобалов в C++
Сообщение13.01.2019, 13:18 


06/04/18
220
SergeyGubanov в сообщении #1368205 писал(а):
Компилируйте с опцией -O0
На олимпиаде такая опция скорее всего будет недоступна :mrgreen:

Цель моего вопроса в том, чтобы разобраться, в каких ситуациях использование глобальных объектов может повлечь проблемы с переносимостью кода, и как этого избежать. Я расписал всю конкретику в начале темы.

 Профиль  
                  
 
 Re: Конструкторы глобалов в C++
Сообщение13.01.2019, 13:41 
Заслуженный участник
Аватара пользователя


02/08/11
5395
Qlin, вы же сами написали ответ на свой вопрос:
Qlin в сообщении #1368177 писал(а):
Нелокальная переменная со статическим классом памяти инициализируемая с побочными эффектами, должна быть инициализирована, даже если она не оdr-используется (3.2, 3.7.1).

 Профиль  
                  
 
 Re: Конструкторы глобалов в C++
Сообщение13.01.2019, 14:20 
Заслуженный участник


28/04/09
1880
В нынешней редакции стандарта самое прямое отношение к Вашему вопросу имеет следующее место:
Стандарт языка C++ в 4-м абзаце параграфа "Dynamic initialization of non-local variables [basic.start.dynamic]" писал(а):
It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized.⁵⁰ ...

⁵⁰⁾ A non-local variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([basic.def.odr], [basic.stc.static]).
Т.е. судя по тексту в сноске, инициализация класса hello должна иметь место, но вот произойдет ли она гарантированно перед вызовом функции main — дело не вполне ясное.

Впрочем, следует заметить, что хотя порядок инициализации глобальных переменных в рамках одной единицы трансляции чётко задан в стандарте (и должен точно соответствовать порядку следования их определений), использовать глобальные объекты в принципе не рекомендуется. Вместо них лучше использовать т.н. мейерсовский синглтон:
Используется синтаксис C++
class Foo
{
    // ...
};

Foo& get_foo()
{
    static Foo foo;

    return foo;
}
В этом случае инициализация объекта foo будет отложена до момента первого вызова функции get_foo. Начиная с C++11, процесс инициализации локального статического объекта foo является по стандарту потокобезопасным (это т.н. magic statics).

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 5 ] 

Модераторы: Karan, PAV, Toucan, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group