std :: cout
est une instance de std :: osstream
. Je peux voir la déclaration de std :: cout
dans un fichier nommé / usr / include / c ++ / 7 / iostream
:
In file included from /opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/iostream:39:0, from <source>:1: /opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/ostream: In function 'int main()': /opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/ostream:384:7: error: 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char; _Traits = std::char_traits<char>]' is protected basic_ostream() ^ <source>:5:18: error: within this context std::ostream os; ^
Et std :: osstream
est défini par typedef std :: basic_ostream
.
Quoi de plus, il semble que vous puissiez 't Créer une instance de std :: osstream
. Voir cette démo Code Snippet :
#include<iostream> int main() { std::ostream os; return 0; }
3 Réponses :
Un compilateur et sa mise en œuvre de la bibliothèque standard peuvent coopérer à l'aide de fonctionnalités non standard qui ne sont pas utilisables par de simples programmeurs.
Ce n'est pas nécessaire dans ce cas car il existe un constructeur public assez standard:
explicit basic_ostream(basic_streambuf<char_type, Traits>* sb);
Si vous avez un streambuf
prêt, vous pouvez créer un objet de type osstream
, tout comme la bibliothèque standard.
Qu'est-ce que streambuf
est exactement un détail d'implémentation caché, mais sur une implémentation typique, c'est probablement un objet d'une classe personnalisée construite à partir de stdout
(le style C
pointeur de fichiers).
comment std :: cout est créé?
Tout d'abord, à partir de https://en.cpreference.com/w / cpp / io / ios_base / init :
std :: ios_base :: init
Cette classe est utilisée pour s'assurer que les flux C ++ par défaut (std :: cin, Std :: cout, etc.) sont correctement initialisés et détruits. [...]
L'en-tête
se comporte comme s'il définit (directement ou
indirectement) une instance de std :: ios_base :: init avec stockage statique
Durée: [...]
meh, faisons un vrai exemple de code. J'utiliserai bibliothèque GCC C ++ . De https: // github.com/gcc-mirror/gcc/blob/master/libstdc%2b%2b-v3/include/std/iostream#l73 , c'est la partie importante:
#include <fstream> #include <ext/stdio_sync_filebuf.h> int main() { __gnu_cxx::stdio_sync_filebuf<char> mybuf_cout_sync(stdout); std::ostream os(&mybuf_cout_sync); os << "Hello world!\n"; return 0; }
Hein. Donc dans globals_io.cc
, std :: cin
/ std :: cout
/ std :: cerr
ne sont rien mais char
des tableaux alignés pour correspondre aux exigences de iStream
/ ostream
. Pourtant, l'en-tête iostream
et ios_init.cc
les déclare comme des externes qui sont des objets réels isttream
/ en tant que tels (en supposant [correctement] ils n'ont pas été initialisés dans ce dernier cas, car il placement
new
est partout dans cette mémoire), et je suppose que le linker est d'accord avec cela parce qu'il se soucie juste Que la quantité correcte de mémoire alignée est là où elle s'attend à ce qu'elle soit? Bizarre.
@Shadowranger Les linkers, en règle générale, ne se soucient même pas de la taille et de l'alignement, bien qu'ils puissent théoriquement ... mais de nombreux compilateurs ne se soucient pas de remplir correctement les champs de taille
dans les fichiers d'objet «Tables de symboles, les lieurs doivent donc y faire face.
@Shadowranger LTO s'en plaindre, mais seulement si vous créez une version statique de libstdc ++ avec LTO, qui est loin de la valeur par défaut. gcc.gnu.org/bugzilla/show_bug.cgi?id=59472 gcc.gnu.org/bugzilla/show_bug.cgi?id=64275 a>
MSVC utilise une ruse similaire pour construire son cout
, cin
, et CERR
, également; Je ne suis pas à jour sur les détails, cependant, la dernière fois que j'ai vérifié était la construction 2010 ou 2015.
Je pense qu'une partie de ce qui manque les réponses actuelles et de ce qui fait partie de votre question:
Le nom std :: cout
est également «magique».
Cela signifie que la bibliothèque standard connaît à ce sujet et fournit les connexions nécessaires spécifiques au système d'exploitation au terminal; en utilisant le système respectif (et spécifique au système d'exploitation) pour la sortie, etc.
Merci pour l'explication. Toute référence? Qu'est-ce que la tuyauterie de fond? Pourriez-vous s'il vous plaît expliquer cela plus en détail pour moi?
Il peut se créer lui-même.
Vous pouvez créer une instance
std :: osstream
, mais vous ne pouvez pas la construire par défaut. Voir ici Pour en savoir plus sur les constructeurs. La page sur std :: cout a plus de détails sur la façon dont il est initialisé - Il s'agit d'un tampon de flux défini par l'implémentation auquel il est connecté, et la mise en œuvre doit également garantir qu'il est initialisé de manière appropriée au début du programme.cout
peut être créé comme une instance d'une classe qui dérive destd :: osstream
@DrewMCGowen mais
cout
est en fait une instance destd :: osstream
autre que dérivé destd :: osstream
.@DrewmcGowen est-ce vraiment vrai? Le standard nécessite que la déclaration soit
extern ostream cout; code >, ce qui semble empêcher
cout
d'être une référence à une classe dérivée.Oups, j'ai menti - je pensais aux pointeurs, mais ici les pointeurs ne sont pas impliqués
@Nathanpierson Merci pour la réponse. Mais le lien ne semble pas très méchant. Il ne me dit pas clairement comment
std :: cout
est implémenté et commentstd :: cout < / code> est créé par le constructeur de
. Pour autant que je puisse voir, l'infomation la plus apparentée est les objets globaux std :: cout et std :: wcout de contrôle de contrôle vers un tampon de flux de type défini par l'implémentation (dérivé de std :: streambuf), associé à la standard c stream de sortie stdout. Et rien de plus.std :: osstream
La norme linguistique définit ce que vous voyez comme un programmeur et ce que vous obtenez. Il n'est pas censé vous dire comment il est mis en œuvre.
@John La spécification est délibérément vague ici pour donner aux implémenteurs de bibliothèque une certaine latitude dans la façon dont ils choisissent de coder les choses. Cela ressemble plus à un contrat qui dit ce qui doit être fait plutôt que de dire à quel point il faut faire spécifiquement.
Oui c'est correct.
std :: basic_ostream
a un constructeur qui prend un pointeur vers un objetstd :: basic_streambuf
.std :: cout
est initialisé à l'aide d'un pointeur sur une instance d'une classe dérivée définie par l'implémentation destd :: basic_streambuf
. Si vous voulez plus de détails, vous devez spécifier la mise en œuvre de la mise en œuvre.@Nathanpierson je vois. Merci pour l'explication détaillée. Je travaille sur
ubuntu
. Après avoir lu votre dernière réponse, je pense que je comprends presque la déclaration de votre lien. Les objets globaux std :: cout et std :: wcout de contrôle de contrôle vers un tampon de flux de type défini par l'implémentation (dérivé de std :: streambuf),Le nom du système d'exploitation ne nous dit pas le nom du compilateur C ++. Veuillez lire l'historique Edit pour voir pourquoi votre question a été modifiée.
Il semble que vous ne serez pas satisfait tant que vous ne voyez pas le code réel d'une implémentation de bibliothèque standard. Ainsi, vous voudrez peut-être parcourir le code de la bibliothèque standard GNU C ++ comme point de départ.
@ user207421 Je vois. Désolé, j'ai mis à jour le message. C'est GCC 4.9.
GCC 4.9 est plutôt vieux. Ne l'utilisez pas.
osstream * cout_ptr = :: new (cout) osstream (:: new (__ cout) __stdoutbuf (stdout, & mb_coout));
juste le placement nouveau dans le code d'initialisation.@John C'est à l'implémentation comment implémenter le comportement spécifié par la norme. Il n'y a pas de réponse unique, il y a exactement ce que chaque implémentation a décidé de faire.
@ n.1.8e9-where's-my-sharem. C'est vraiment hors de mon contrôle. Je n'ai pas le choix, en effet.