 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Rene Moehring Guest
|
Posted: Wed Jun 22, 2005 8:00 am Post subject: Erstellung des cout-Objekts |
|
|
Wie wird eigentlich das cout-Objekt in C++ erstellt, so daß es mehr oder
weniger automagisch vorhanden ist. Globale Variable würde ich ja sonst
überall mit extern deklarieren und in einem File dann das entsprechende
Objekt konstruieren. Bei cout erstellt man aber ja nicht explizit. Wo
kommt das her?
--
I'm not a racist. I hate everyone equally!
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Wed Jun 22, 2005 9:03 am Post subject: Re: Erstellung des cout-Objekts |
|
|
Rene Moehring <rene_moehring (AT) gmx (DOT) de> writes:
| Quote: | Wie wird eigentlich das cout-Objekt in C++ erstellt, so daß es mehr
oder weniger automagisch vorhanden ist. Globale Variable würde ich
ja sonst überall mit extern deklarieren und in einem File dann das
entsprechende Objekt konstruieren. Bei cout erstellt man aber ja
nicht explizit. Wo kommt das her?
|
Diese Deklaration steht im Standard-Header <iostream>.
Die C++-Implementation muss sicherstellen, dass die in <iostream>
deklarierten Objekte initialisiert werden, wenn sie im Programm
gebraucht werden. Wie die Implementation das sicherstellt, ist ihr
überlassen.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Jun 22, 2005 11:03 am Post subject: Re: Erstellung des cout-Objekts |
|
|
Rene Moehring wrote:
| Quote: | Wie wird eigentlich das cout-Objekt in C++ erstellt, so daß es
mehr oder weniger automagisch vorhanden ist. Globale Variable
würde ich ja sonst überall mit extern deklarieren und in einem
File dann das entsprechende Objekt konstruieren. Bei cout
erstellt man aber ja nicht explizit. Wo kommt das her?
|
Formell betrachtet: implementation defined. In der Praxis gibt's
wahrscheinlich in der Bibliothek auch eine Objekt-Datei mit
einer Definition von cout, genau wie bei deiner statischen
Variablen. Der einzige Unterschied: die Implementierung muss
irgendwie garantieren, dass cout auch in allen deinen statischen
Constructoren zur Verfügung steht. Wenn sie nichts über der
Reihenfolge der Construction garantieren kann, muss sie
irgendwie mit basic_ios<>::Init tricksen.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rene Moehring Guest
|
Posted: Wed Jun 22, 2005 11:31 am Post subject: Re: Erstellung des cout-Objekts |
|
|
On Wed, 22 Jun 2005 11:03:51 +0200, Thomas Maeder wrote:
| Quote: | Rene Moehring <rene_moehring (AT) gmx (DOT) de> writes:
Wie wird eigentlich das cout-Objekt in C++ erstellt, so daß es mehr
oder weniger automagisch vorhanden ist. Globale Variable würde ich
ja sonst überall mit extern deklarieren und in einem File dann das
entsprechende Objekt konstruieren. Bei cout erstellt man aber ja
nicht explizit. Wo kommt das her?
Diese Deklaration steht im Standard-Header <iostream>.
Die C++-Implementation muss sicherstellen, dass die in
deklarierten Objekte initialisiert werden, wenn sie im Programm
gebraucht werden. Wie die Implementation das sicherstellt, ist ihr
überlassen.
OK, welche Möglichkeiten so etwas zu tun stehen denn zur Verfügung? Ich |
hab nämlich einen schönen Stream gebastelt, den ich dann am liebsten
genauso automagisch verwendeb können möchte.
--
I'm not a racist. I hate everyone equally!
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Wed Jun 22, 2005 11:51 am Post subject: Re: Erstellung des cout-Objekts |
|
|
Rene Moehring wrote:
| Quote: | On Wed, 22 Jun 2005 11:03:51 +0200, Thomas Maeder wrote:
Rene Moehring <rene_moehring (AT) gmx (DOT) de> writes:
Wie wird eigentlich das cout-Objekt in C++ erstellt, so daß es mehr
oder weniger automagisch vorhanden ist. Globale Variable würde ich
ja sonst überall mit extern deklarieren und in einem File dann das
entsprechende Objekt konstruieren. Bei cout erstellt man aber ja
nicht explizit. Wo kommt das her?
Diese Deklaration steht im Standard-Header <iostream>.
Die C++-Implementation muss sicherstellen, dass die in
deklarierten Objekte initialisiert werden, wenn sie im Programm
gebraucht werden. Wie die Implementation das sicherstellt, ist ihr
überlassen.
OK, welche Möglichkeiten so etwas zu tun stehen denn zur Verfügung?
|
Der Implementation? Alle.
| Quote: | Ich hab nämlich einen schönen Stream gebastelt, den ich dann am liebsten
genauso automagisch verwendeb können möchte.
|
Ach so. Naja, für dich gibt es keine portable Möglichkeit. Für cout darf der
Compiler/Linker intern alle möglichen fiesen Tricks verwenden, die dem
Benutzer aber nicht zur Verfügung stehen.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Thomas Kemmer Guest
|
Posted: Wed Jun 22, 2005 12:46 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Rolf Magnus <ramagnus (AT) t-online (DOT) de> writes:
| Quote: | Ach so. Naja, für dich gibt es keine portable Möglichkeit. Für cout darf der
Compiler/Linker intern alle möglichen fiesen Tricks verwenden, die dem
Benutzer aber nicht zur Verfügung stehen.
|
Nun, eine Möglichkeit wäre der allseits beliebte "global init trick"
(auch unter anderen Bezeichnungen bekannt). Beruht darauf, dass ein
Objekt einer speziellen Init-Klasse "static" im Header deklariert
wird.
x.h:
class X {
/* ... */
void init();
public:
/* ... */
class Init {
static int count;
public:
Init();
};
};
extern X global_x;
static X::Init local_x_init;
x.cpp:
int X::Init::count = 0;
X global_x;
X::Init::Init()
{
if (count++ == 0) {
global_x.init();
}
}
Oder so ähnlich...
In jeder Translation Unit (Object File) die x.h inkludiert ist damit
sichergestellt, dass der Konstruktor des jeweiligen local_x_init vor
der ersten Verwendung von global_x ausgeführt wird. Zumindest für den
Single-Threaded Fall ;-)
- Thomas
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
brf Guest
|
Posted: Wed Jun 22, 2005 1:57 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Compiler können das machen wie sie wollen. Im Standard ist das mit den
Anweisungen vorgeschlagen, die hier in didaktischer, nicht
Standardreihenfolge grob zitiert werden:
in <iostream>: extern ostream cout; und ostream cout;
in <iosfwd>: typedef basic_ostream<char> ostream;
in <ostream>: template <class charT, class traits=char_traits
class basic_ostream : virtual public basic_ios<charT,
traits>
{
jedem Menge C++ Code
};
Interessant ist, dass Stroustrup das typedef aus C++ entfernen wollte
und mit den templates doch wieder benötigt.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Wed Jun 22, 2005 6:45 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Rene Moehring wrote:
| Quote: | OK, welche Möglichkeiten so etwas zu tun stehen denn zur Verfügung? Ich
hab nämlich einen schönen Stream gebastelt, den ich dann am liebsten
genauso automagisch verwendeb können möchte.
|
Wo möchtest du ihn verwenden? Wenn du mit der Verwendung erst in 'main'
beginnst, reicht es, ihn einfach in einem Header zu deklarieren und in
einer .cpp deiner Wahl zu definieren. Wie eine normale Variable auch.
Wenn er auch schon in Konstruktoren zur Verfügung stehen soll, musst du
Tricksen:
----8<----rmstream.h----8<----
#ifndef RMSTREAM_H
#define RMSTREAM_H
class rmstream { ... };
inline rmstream&
get_rmstream()
{
static rmstream x (Konstruktorparameter);
return x;
}
#endif
----8<--------8<--------8<----
IMHO hat diese Realisierung wesentliche Vorteile gegenüber dem 'global
init trick':
- du kannst den Konstruktor direkt aufrufen ohne irgendwelche blöden
init-Funktionen zu benötigen. Dein Objekt muss also keinen
"halboffenen" Zustand implementieren.
- die Initialisierung findet *einmal* statt. Beim 'global init trick'
steht der Aufruf der Init-Funktion so oft in der .exe, wie die
Headerdatei eingebunden wurde. Dadurch wird die .exe größer, und
außerdem muss das Betriebssystem beim Start noch vor main fast
das komplette Programm laden, weil ja in fast jedem Modul so ein
Codeschnipsel steht. Demand-Loading wird damit ad absurdum geführt.
Nachteile sind:
- der Stream wird erst bei der ersten Verwendung konstruiert, nicht zum
Programmstart.
- Klammern beim Aufruf:
get_rmstream() << "Hello, worldn";
Wenn du damit partout nicht leben kannst, mach halt ein Makro
#define rmstream get_rmstream()
Stefan
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Thu Jun 23, 2005 3:12 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Rolf Magnus wrote:
| Quote: | Rene Moehring wrote:
On Wed, 22 Jun 2005 11:03:51 +0200, Thomas Maeder wrote:
Rene Moehring <rene_moehring (AT) gmx (DOT) de> writes:
Wie wird eigentlich das cout-Objekt in C++ erstellt, so
daß es mehr oder weniger automagisch vorhanden
ist. Globale Variable würde ich ja sonst überall mit
extern deklarieren und in einem File dann das
entsprechende Objekt konstruieren. Bei cout erstellt man
aber ja nicht explizit. Wo kommt das her?
Diese Deklaration steht im Standard-Header <iostream>.
Die C++-Implementation muss sicherstellen, dass die in
iostream> deklarierten Objekte initialisiert werden, wenn
sie im Programm gebraucht werden. Wie die Implementation
das sicherstellt, ist ihr überlassen.
|
Zuerst: der oberstehende Absatz ist falsch. Laut der Norm
besteht keine automatische Garantie, dass man cout u.a. vor main
benutzen kann. Die einzige Garantie, dass ich habe, ist
(§27.3/2): "The objects are constructed, and the associations
are established at some time prior to or during first time an
object of class basic_ios<charT,traits>::Init is constructed,
and in any case before the body of main begins execution."
Gibt es kein Objekt von type basic_ios<charT,traits>, dann hast
du absolut keine Garantie.
Obwohl nicht von der Norm verlangt, glaube ich, dass die meisten
Implementierungen ein statisches Objekt dieses Typs im Header
iostream vereinbaren. Einfach weil diese Vereinbarung war in der
klassischen Streams pflicht. Vorsicht ist aber trotzem verlangt.
Hast du in einer Datei etwas wie:
MeinTyp statischeVariable ;
MeinTyp::MeinTyp()
{
externeFunktion() ;
}
und in einer anderen:
#include <iostream>
#include <ostream>
static std::ios::Init sicherIstSicher ;
void
externeFunktion()
{
std::cout << "...n" ;
}
hast du immer keine Garantie, weil der Constructor
statischeVariable kann aufgerufen werden, bevor der Constructor
von sicherIstSicher.
Meistens hat alles trotzdem gut funktionniert, weil die gängigen
Compiler die einzigen Moduln initialisierten, in der umgekehrten
Reihenfolge, die die Moduln von Linker eingezogen wurden, und
dass es immer viele Vereinbarungen von ios::Init tief in der
Bibliothek gegeben hat, wo die gewöhlicherweise unter den
letzten einbezogen wurden. Derjenige, der auch sichere Software
Wert liegt, hat aber wohl gemerkt, dass Wörter wie "Meistens"
und "gewöhnlicherweise" kein stabiler Grund sind, um
zuverlässiges Software aufzubauen.
In der Tat gibt es keine gute Lösung. Wenn der Autor von MeinTyp
nicht weiß, dass externeFunktion cout benutzt, und der Autor von
externeFunktion nicht weiß, dass seine Funktion von einem
Constructor eines statischen Objektes aufgerufen wird. Streng
genommen muss es heißen, dass ob eine Funktion von einem
statischen Constructor aufgerufen werden darf, oder nicht,
gehört zu seinem Vertrag. Und wenn der Vertrag nicht
ausdrücklich lautet, dass sie es darf, dann darf man sie nicht
in solchen Fällen benutzen. Und wenn der Vertrag lautet, dass
sie aufgerufen werden darf, dann muss die Funktion lauten:
void
externeFunktion()
{
std::ios::Init sicherIstSicher ;
std::cout << "...n" ;
}
Leiter muss ich zugeben, dass ich soviel Strenge nie gesehen
habe.
Bei der Destruction statischer Objekte bestehen ähnliche
Probleme. Laut Norm werden cout u.a. geflusht (aber nie
destruktiert), wenn die letzte Instanz ios::Init destruktiert
wird. Dass kann aber vorkommen, bevor der Destructor deines
statischen Objektes aufgerufen wird. Um von statischen
Destructoren aufgerufen werden, muss die Funktion selbst einen
Flush machen. (Noch ein Grund, std::endl bevorzuziehen.)
| Quote: | OK, welche Möglichkeiten so etwas zu tun stehen denn zur Verfügung?
Der Implementation? Alle.
Ich hab nämlich einen schönen Stream gebastelt, den ich dann
am liebsten genauso automagisch verwendeb können möchte.
Ach so. Naja, für dich gibt es keine portable Möglichkeit.
|
Nicht 100%-ig, aber...
Es funktionniert meistens, wenn man einen sonderen Constructor
zur Verfügung stellt, die absolut nichts tut. (In Prinzip dart
der Compiler systematisch die Speicher überschreiben, bevor er
den Constructor aufruft. Praktisch tut es keiner.) Objekte wie
cout werden vereinbart, diese Constructor zu verwenden, z.B.:
MyStream myCOut( dummyDamitNichtsGemachtWird ) ;
Dann, in MyStream::Init :
Init::Init()
{
static int magic = 0 ;
if ( magic == 0 ) {
magic = 1 ;
new ( &myCOut ) MyStream( dieRichtigeParameter ) ;
}
++ magic ;
}
Init::~Init()
{
-- magic ;
if ( magic == 1 ) {
myCOut.flush() ;
}
}
(Dieses Trick heißt "tricky counter", und wurde von Jerry
Schwarz erfunden.)
Eine einfachere Möglichkeit, die ich gelegentlich sogar benutze,
ist, die Klasse so zu schreiben, dass die Nul-Initialisierung
genugt, und dass der Constructor nicht tut. Dass ist meistens
leichter, als man vorstellt, wenn die tatsächliche
Initialisierung "lazy" ausgeführt wird.
| Quote: | Für cout darf der Compiler/Linker intern alle möglichen fiesen
Tricks verwenden, die dem Benutzer aber nicht zur Verfügung
stehen.
|
Die meisten aber benutzen kein Trick, ausser diejenigen, die ich
gerade ausgeführt habe.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Thu Jun 23, 2005 3:20 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Stefan Reuther wrote:
| Quote: | Rene Moehring wrote:
OK, welche Möglichkeiten so etwas zu tun stehen denn zur
Verfügung? Ich hab nämlich einen schönen Stream gebastelt,
den ich dann am liebsten genauso automagisch verwendeb
können möchte.
Wo möchtest du ihn verwenden? Wenn du mit der Verwendung erst
in 'main' beginnst, reicht es, ihn einfach in einem Header zu
deklarieren und in einer .cpp deiner Wahl zu definieren. Wie
eine normale Variable auch.
Wenn er auch schon in Konstruktoren zur Verfügung stehen soll,
musst du Tricksen:
----8<----rmstream.h----8<----
#ifndef RMSTREAM_H
#define RMSTREAM_H
class rmstream { ... };
inline rmstream&
get_rmstream()
{
static rmstream x (Konstruktorparameter);
return x;
}
#endif
----8<--------8<--------8<----
IMHO hat diese Realisierung wesentliche Vorteile gegenüber dem
'global init trick':
- du kannst den Konstruktor direkt aufrufen ohne irgendwelche blöden
init-Funktionen zu benötigen. Dein Objekt muss also keinen
"halboffenen" Zustand implementieren.
- die Initialisierung findet *einmal* statt. Beim 'global init trick'
steht der Aufruf der Init-Funktion so oft in der .exe, wie die
Headerdatei eingebunden wurde. Dadurch wird die .exe größer, und
außerdem muss das Betriebssystem beim Start noch vor main fast
das komplette Programm laden, weil ja in fast jedem Modul so ein
Codeschnipsel steht. Demand-Loading wird damit ad absurdum geführt.
Nachteile sind:
- der Stream wird erst bei der ersten Verwendung konstruiert, nicht zum
Programmstart.
- Klammern beim Aufruf:
get_rmstream() << "Hello, worldn";
Wenn du damit partout nicht leben kannst, mach halt ein Makro
#define rmstream get_rmstream()
|
Noch größeren Nachteilen :
- der Stream darf nicht in multi-threaded Umgebungen benutzt
werden (mindestens mit den meisten Compilern).
- ein Problem kann noch in statischen Destructoren bestehen.
Beide kann man fast vollständig erledigen, indem man den
statischen Objekt durch einen Zeiger ersetzt:
static rmstream* unserObjet = &get_rmstream() ;
rmstream&
get_rmstream()
{
if ( unserObjekt == NULL ) {
unserObjekt = new rmstream( ... ) ;
}
return *unserObjekt ;
}
Die etwa kommische Initialisierung von unserObjekt
gewährleistet, dass der Zeiger vor dem Aufruf von main
initialisiert wird; wenn die Threads erst nach dem Aufruf von
main gestartet werden, dann wird unserObjekt nie geändert, nach
dem Starten der Threads (und damit darf man ohne Lock darauf
angreifen).
Hier auch wird das Objekt nie destructed. Was in diesem Fall
Vorteilhaft ist.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Dirk Jagdmann Guest
|
Posted: Fri Jun 24, 2005 12:36 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
| Quote: | OK, welche Möglichkeiten so etwas zu tun stehen denn zur Verfügung? Ich
hab nämlich einen schönen Stream gebastelt, den ich dann am liebsten
genauso automagisch verwendeb können möchte.
|
Damit habe ich mich auch mal beschäftigt. Ich habe das wie folgt gelöst:
1) In dem Header, der meinen Stream deklariert immer ein "streaminit"
Objekt statisch anlegen. Das Konstruktor dieses Objektes der Objektes
initialisiert dann deinen Stream. Da globale Variablen immer konstruiert
werden bevor eine Funktionen im dem jeweiligen File ausgeführt wird ist
sichergestellt, dass dein Stream initialisiert ist. Beispiel:
mystream.hpp:
class mystream_init {
static int init;
public: mystream_init()
};
static mystream_init ___this_is_an_ugly_name;
// dein eigentlicher Stream
class mystream { };
EOF
2) Im Source File der entsprechende Code:
mystream.cpp:
int mystream_init::init; // ist automatisch 0 (wichtig, hier darf
// *nicht* explizit initialisiert werden
mystream_init::mystream_init() {
if(++count==1) {
//init your stream
}
}
3) Jetzt gibt es aber das Problem, dass du deinen Stream ja als globales
Objekt irgendwo deklarieren und auch definieren musst. Das deklarieren
ist noch einfach. Einfach in mystream.hpp folgenden einfügen:
"extern mystream mycout;"
Wenn du jetzt aber z.B. in mystream.cpp einfach "mystream mycout;" als
Objekt anlegst, dann bekommst du ein Henne/Ei Problem mit deiner
initialisierung in mystream_init. Die/Eine Lösung dazu habe ich mir beim
GCC abgeschaut. Das Objekt wird nicht als "mystream" alloziert, sondern
als ein char[] mit der Größe von mystream. Dann in mystream_init() mit
placement new initialisiert. Also ungefähr so (dazu brauchen wir noch
ein drittes File):
mystream2.cpp:
#include "mystream.hpp"
typedef char fake_mystream[sizeof(mystream)];
fake_mystream mycout;
EOF
Der Code in mystream.cpp bei "//init your stream" dann so:
"new (&mycout) mystream;"
-------------------------------
Was ich mich bis heute frage ist, warum (zumindest gcc) das ganze linken
kann, obwohl (wegen Namemangling) meine fake definition von mycout ja
eigentlich eine andere Signatur haben sollte. Aber es funktioniert.
Als vollständiges Beispiel kannst du dir die libstdc vom gcc anschauen,
oder meine Stream Klasse: http://llg.cubic.org/tools/dojstream/
Solltest du mit Microsoft Sachen arbeiten geht das ganze auch einfacher
mit Hilfe des "#pragma init_seg(lib)". Siehe dazu meinen dojstream.
--
---> doj / cubic
----> http://cubic.org/~doj
-----> http://llg.cubic.org
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Jun 24, 2005 1:46 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Dirk Jagdmann wrote:
| Quote: | 3) Jetzt gibt es aber das Problem, dass du deinen Stream ja
als globales Objekt irgendwo deklarieren und auch definieren
musst. Das deklarieren ist noch einfach. Einfach in
mystream.hpp folgenden einfügen: "extern mystream mycout;"
Wenn du jetzt aber z.B. in mystream.cpp einfach "mystream
mycout;" als Objekt anlegst, dann bekommst du ein Henne/Ei
Problem mit deiner initialisierung in mystream_init. Die/Eine
Lösung dazu habe ich mir beim GCC abgeschaut. Das Objekt wird
nicht als "mystream" alloziert, sondern als ein char[] mit der
Größe von mystream. Dann in mystream_init() mit placement new
initialisiert. Also ungefähr so (dazu brauchen wir noch ein
drittes File):
mystream2.cpp:
#include "mystream.hpp"
typedef char fake_mystream[sizeof(mystream)];
fake_mystream mycout;
EOF
Der Code in mystream.cpp bei "//init your stream" dann so:
"new (&mycout) mystream;"
-------------------------------
Was ich mich bis heute frage ist, warum (zumindest gcc) das
ganze linken kann, obwohl (wegen Namemangling) meine fake
definition von mycout ja eigentlich eine andere Signatur haben
sollte. Aber es funktioniert.
|
Bei den meisten Compilern (und darunten g++) sind nur
Funktionsnamen gemangelt, nicht aber Variablennamen. Dagegen
muss man auf den Alignement aufpassen; ein char[] wird nicht
unbedingt für eine Klasse mit Zeigern aligniert. Bei g++ gibt es
Erweiterungen, um einen bestimmten Alignment zu zwingen; dazu
ist es möglich, dass die erste Variable in eine
Übersetzungseinheit immer richtig aligniert wird, und dass die
Autoren dieses Stückes Code damit rechnen.
Bei einfachen Klassen kannst du machen, wie ich es vorgeschlagen
habe, mit einem nichts tuenden Constructor. Dann muss man aber
mit Basisklassen und Datenmitglieder vorsichtig sein; ihre
Constructore mßssen auch in diesem Fall nichts tun.
Wenn es nicht anders geht, besteht immer die Möglichkeiten,
einen ausreichend großen und richtig alignierten Block in
Assembler anzulegen.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Dirk Jagdmann Guest
|
Posted: Fri Jun 24, 2005 4:29 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
| Quote: | Bei den meisten Compilern (und darunten g++) sind nur
Funktionsnamen gemangelt, nicht aber Variablennamen. Dagegen
|
Das stimmt natürlich.
| Quote: | muss man auf den Alignement aufpassen; ein char[] wird nicht
unbedingt für eine Klasse mit Zeigern aligniert. Bei g++ gibt es
Erweiterungen, um einen bestimmten Alignment zu zwingen; dazu
ist es möglich, dass die erste Variable in eine
Übersetzungseinheit immer richtig aligniert wird, und dass die
Autoren dieses Stückes Code damit rechnen.
Bei einfachen Klassen kannst du machen, wie ich es vorgeschlagen
habe, mit einem nichts tuenden Constructor. Dann muss man aber
mit Basisklassen und Datenmitglieder vorsichtig sein; ihre
Constructore mßssen auch in diesem Fall nichts tun.
|
Stimmt auch, aber ich denke ähnlich wie bei mir wird auch Rene in seinem
stream Konstruktor etwas machen wollen, deshalb mein Vorschlag.
| Quote: | Wenn es nicht anders geht, besteht immer die Möglichkeiten,
einen ausreichend großen und richtig alignierten Block in
Assembler anzulegen.
|
Stimmt, aber ich denke gerade aus Gründen von Portabilität und einfacher
Verständlichkeit ist dann in kleiner Block von "#ifdef MEINCOMPILER"
gepaart mit den Compilerspezifischen Anweisungen die Variable richtig zu
alignen sinnvoller.
--
---> doj / cubic
----> http://cubic.org/~doj
-----> http://llg.cubic.org
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Mon Jun 27, 2005 12:20 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
Dirk Jagdmann wrote:
| Quote: | Bei den meisten Compilern (und darunten g++) sind nur
Funktionsnamen gemangelt, nicht aber Variablennamen. Dagegen
Das stimmt natürlich.
muss man auf den Alignement aufpassen; ein char[] wird nicht
unbedingt für eine Klasse mit Zeigern aligniert. Bei g++
gibt es Erweiterungen, um einen bestimmten Alignment zu
zwingen; dazu ist es möglich, dass die erste Variable in
eine Übersetzungseinheit immer richtig aligniert wird, und
dass die Autoren dieses Stückes Code damit rechnen.
Bei einfachen Klassen kannst du machen, wie ich es
vorgeschlagen habe, mit einem nichts tuenden
Constructor. Dann muss man aber mit Basisklassen und
Datenmitglieder vorsichtig sein; ihre Constructore mßssen
auch in diesem Fall nichts tun.
Stimmt auch, aber ich denke ähnlich wie bei mir wird auch Rene
in seinem stream Konstruktor etwas machen wollen, deshalb mein
Vorschlag.
|
Vielleicht war ich nicht ganz klar. Das Problem ist, dass das
Objekt zweimal konstruiert wird: einmal durch placement-new im
Constructor des Init-Objektes, und einmal, wenn es ganz normal
konstruiert wird, bei der statischen Initialisierung. Der durch
placement-new aufgerufene Constructor soll wohl tun, was zu tun
ist. Der von der statischen Initialisierung aufgerufenen
Constructor dagegen darf nichts tun.
Ich habe diesen Vorgang ein Paar mal verwendet; ich habe auch ab
und zu einen nichts tuenden Constructor mit Klassen verwended,
die mit der Null-Initialisierung zu Recht kommen. In beiden
Fällen gibt es auch Constructoren, die etwas tun, für den Fall,
wo das Objekt nicht statisch angelegt wird.
| Quote: | Wenn es nicht anders geht, besteht immer die Möglichkeiten,
einen ausreichend großen und richtig alignierten Block in
Assembler anzulegen.
Stimmt, aber ich denke gerade aus Gründen von Portabilität und
einfacher Verständlichkeit ist dann in kleiner Block von
"#ifdef MEINCOMPILER" gepaart mit den Compilerspezifischen
Anweisungen die Variable richtig zu alignen sinnvoller.
|
Du gehst aber davon aus, dass so eine Anweisung gibt. Ich bin
nicht so sicher.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rene Moehring Guest
|
Posted: Mon Jun 27, 2005 1:26 pm Post subject: Re: Erstellung des cout-Objekts |
|
|
On 27 Jun 2005 05:20:18 -0700, [email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: | Dirk Jagdmann wrote:
Bei den meisten Compilern (und darunten g++) sind nur
Funktionsnamen gemangelt, nicht aber Variablennamen. Dagegen
Das stimmt natürlich.
muss man auf den Alignement aufpassen; ein char[] wird nicht
unbedingt für eine Klasse mit Zeigern aligniert. Bei g++
gibt es Erweiterungen, um einen bestimmten Alignment zu
zwingen; dazu ist es möglich, dass die erste Variable in
eine Übersetzungseinheit immer richtig aligniert wird, und
dass die Autoren dieses Stückes Code damit rechnen.
Bei einfachen Klassen kannst du machen, wie ich es
vorgeschlagen habe, mit einem nichts tuenden
Constructor. Dann muss man aber mit Basisklassen und
Datenmitglieder vorsichtig sein; ihre Constructore mßssen
auch in diesem Fall nichts tun.
Stimmt auch, aber ich denke ähnlich wie bei mir wird auch Rene
in seinem stream Konstruktor etwas machen wollen, deshalb mein
Vorschlag.
Vielleicht war ich nicht ganz klar. Das Problem ist, dass das
Objekt zweimal konstruiert wird: einmal durch placement-new im
Constructor des Init-Objektes, und einmal, wenn es ganz normal
konstruiert wird, bei der statischen Initialisierung. Der durch
placement-new aufgerufene Constructor soll wohl tun, was zu tun
ist. Der von der statischen Initialisierung aufgerufenen
Constructor dagegen darf nichts tun.
Ich habe diesen Vorgang ein Paar mal verwendet; ich habe auch ab
und zu einen nichts tuenden Constructor mit Klassen verwended,
die mit der Null-Initialisierung zu Recht kommen. In beiden
Fällen gibt es auch Constructoren, die etwas tun, für den Fall,
wo das Objekt nicht statisch angelegt wird.
Wenn es nicht anders geht, besteht immer die Möglichkeiten,
einen ausreichend großen und richtig alignierten Block in
Assembler anzulegen.
Stimmt, aber ich denke gerade aus Gründen von Portabilität und
einfacher Verständlichkeit ist dann in kleiner Block von
"#ifdef MEINCOMPILER" gepaart mit den Compilerspezifischen
Anweisungen die Variable richtig zu alignen sinnvoller.
Du gehst aber davon aus, dass so eine Anweisung gibt. Ich bin
nicht so sicher.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
Ich werf mal zwischendurch ein Danke ind die Runde. Ihr habt mir schon
gut weiter geholfen.
--
I'm not a racist. I hate everyone equally!
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|