2015-10-13 6 views
1

std::cout объект объявлен в файле iostream заголовка, какКак работает std :: cout?

namespace std _GLIBCXX_VISIBILITY(default) 
{ 
... 
extern ostream cout; 
... 
} 

Теперь я опуская префикс std::.

Итак, насколько я понимаю, cout является «просто» объектом типа ostream. Я начал задаваться вопросом, почему материал печатается на экран с cout, а не с другими объектами ostream, поэтому я попытался создать объект типа ostream, но компилятор мне не позволил. На самом деле, ostream - это просто псевдоним для basic_ostream<char>, и конструктор по умолчанию для этого типа защищен. Хорошо, подумал я. Но потом я подумал: почему для начала начинается декларация cout? Почему это не вызывает ошибку компилятора?

Я снова попытался объявить ostream с ключевым словом extern, такие как

extern ostream os; 
os << "Will you compile?\n"; 

и на этот раз я получил неопределенную ссылочную ошибку зева. Тогда вопрос просто переходит к следующему: есть ли «определение» cout где-то еще? Если да, то где?

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

Спасибо.

+0

Huh what ?? Где вы на самом деле определили 'os'? –

+1

@ πάνταῥεῖ Нигде, следовательно, ошибка компоновщика, упомянутая в вопросе. – hvd

+2

Ключевое слово 'extern' означает, что указанная переменная определена в другом месте, и компилятору не нужно беспокоиться о том, где до времени связывания. Итак, чтобы ответить «есть ли определение« cout »где-то еще?» Да, должно быть. –

ответ

5

Я начал задаваться вопросом, почему материал печатается на экране с соиЬ, а не с другими объектами ostream,

Поскольку std::cout использует буфер потока, который связан с stdout устройством.

поэтому я попытался создать объект типа ostream, но компилятор мне не позволил. На самом деле, ostream - это просто псевдоним для basic_ostream, и конструктор по умолчанию для этого типа защищен. Хорошо, подумал я. Но потом я подумал: почему начинается декларация cout legal? Почему это не вызывает ошибку компилятора?

Потому что это объявление, а не определение, поэтому он не вызывает никакого конструктора. Может быть, вы должны прочитать о том, что означает extern.

Объявление с extern просто говорит, что в программе есть объект, определенный в программе, который имеет тип ostream и называется cout. Поскольку вы действительно не давали такого определения, вы получаете ошибки компоновщика.

приблизительно имитировать std::cout вы могли бы сделать это в некотором .cpp файле:

namespace { 
    std::ofstream fake_cout("/dev/stdout"); 
} 
std::ostream cout(fake_cout.rdbuf()); 

Это создает fstream, который пишет /dev/stdout затем связывает ostream под названием cout с его потоком буфера.

Это не хорошая симуляция реального std::cout, потому что она не гарантирует, что поток инициализирован, прежде чем любые другие глобальные переменные попытаются использовать его, что делает реальный.

+0

Спасибо за пример! По какой-то причине я не думал, что определение cout находится в некотором источнике (или в библиотеке), а не в заголовках. Конечно, я не мог найти его! Ваш пример очень полезен, потому что он также заставил меня обнаружить stdout/err/внутри папки/dev (мне все равно нужно много узнать о системе unix и корневом дереве). Спасибо! – bartgol

+0

Кроме того, почему 'std :: cout' гарантированно инициализирует поток до того, как любой другой глобальный пытается его использовать, пока моя личная реализация не будет? – bartgol

+1

Поскольку порядок инициализации глобалов в разных объектах не указан, см. Https://isocpp.org/wiki/faq/ctors#static-init-order. В стандартной библиотеке приняты особые меры предосторожности для обеспечения 'std :: cin',' std :: cout' и 'std :: cerr' инициализируются перед объектами, которые пытаются их использовать, как правило, используя [Schwarz Counter] (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter) , –

4

есть определение «cout» в другом месте? Если да, то где?

Да, в реализации libstdC++ стандартной библиотеки C++ есть определение cout. Это определение не выполняется так, как это принято в стандартном C++. Это нормально, потому что реализация стандартной библиотеки C++ не должна быть написана на стандартном C++, ее нужно просто написать так, как понимает остальная часть реализации.

+0

Спасибо! Я действительно задавался вопросом, где это определение, поскольку оно не было в папке include C++, где все стандартные заголовки. Но это имеет смысл: объявляется в стандартных заголовках и определяется в источниках (то есть в библиотеке libstdC++), где он создается с использованием буфера ОС. Теперь ясно. Мне не хватало того факта, что библиотека std не только с заголовками, но и с ... библиотекой! знак равно – bartgol

Смежные вопросы