О std::cout, зачем использовать extern вместо шаблона singleton

Я прочитал эффективный C++, о котором упоминается в пункте 04

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

Я думаю, что «глобальный и единственный объект» должен быть одноэлементным шаблоном, а не внешним объектом после того, как я прочитал этот пункт.

например, объект ввода-вывода (std::cout)

Но std::cout кажется внешним объектом. (http://www.cplusplus.com/reference/iostream/cout/ )

Я смущен этим.

изменить: добавить код

Я захватываю некоторый код из этой книги.

Во-первых, это плохой код:

class FileSystem {
// from your library’s header file
public:
 ...std::size_t numDisks( ) const;
// one of many member functions...
}; 
extern FileSystem tfs;

относительный порядок инициализации нелокальных статических объектов, определенных в разных единицах трансляции, не определен.

Таким образом, вышеупомянутый код может быть ошибкой, когда я вызываю tfs.

Потому что tfs может не завершить инициализацию.

Код рекомендации:

class FileSystem { ... }; // as before
FileSystem& tfs()
{
  static FileSystem fs;
  return fs;
}
class Directory { ... };// as beforeDirectory::Directory( params )
Directory::Directory( params ) // as before, except references to tfs are 
                               //now to tfs( )
{
...
std::size_t disks = tfs().numDisks( );
...
}
Directory& tempDir()
{
  static Directory td(params);
  return td;
}

person curlywei    schedule 20.07.2019    source источник
comment
Потому что C++ был создан по образцу C, который имеет глобальные переменные stdin/stdout/stderr.   -  person melpomene    schedule 20.07.2019
comment
зачем использовать singleton, когда можно использовать extern   -  person apple apple    schedule 20.07.2019
comment
Кстати, проблемы с порядком инициализации (почти) не возникнут для std::cout.   -  person apple apple    schedule 20.07.2019
comment
Связанные чтения: stackoverflow.com/questions/8784892 / en.cppreference.com/w/cpp/io/ios_base /Инициализация   -  person Bob__    schedule 20.07.2019


Ответы (2)


Использование переменной extern обеспечивает (субъективно) более приятный синтаксис

std::cout << stuff;

Подчеркивая, что стандартный поток является уникальным объектом, а не результатом вызова какой-либо функции. Поскольку потоковая передача предназначена для выполнения в потоковых объектах, использование объектной нотации лучше с ней связано.

Что касается фиаско статического порядка инициализации, стандартная библиотека избегает его, используя счетчик Шварца. способ инициализации. Инициализация происходит в четко определенном порядке, поскольку включение iostream добавляет специальный глобальный объект типа Init в том числе ТУ. Конструктор объекта обрабатывает инициализацию потока перед его первым использованием, каким бы оно ни было.

person StoryTeller - Unslander Monica    schedule 20.07.2019
comment
Спасибо! Ключевое слово похоже на Schwarz Counter - person curlywei; 20.07.2019

Потому что C++ выбрал более сложный подход, получив эффективность и простоту прямого доступа к объектам и все же избежав фиаско статического порядка инициализации.

Как?

Стандартные потоки С++ на самом деле не инициализируются статически. Вместо этого #include-ing <iostream> определяет глобальный статический объект типа std::ios_base::Init, который управляет глобальным счетчиком ссылок, а вместе с ним и инициализацией потоки С++.

По крайней мере, так указано, но всегда есть правило как-если< /а>.

person Deduplicator    schedule 20.07.2019