rik
Autor
Benutzerprofil
Anmeldungsdatum: 18.05.2006
Beiträge: 36
|
rik Autor
01:28:56 12.02.2010 Titel: |
|
Zitieren |
| Chris Lux schrieb: | Hi,
Laut Standard wird aber vor dem copy-Event ein delete-Event auf der zu überschreibenden Instanz aufgerufen.
|
Ich verwende hauptsächlich den Visual Studio 2005 Compiler, der sich diesbezüglich leider nicht ganz so standardkonform verhält.
(delete-Event wird vor dem Kopieren nicht aufgerufen)
| Chris Lux schrieb: |
static void callback(std::ios_base::event ev, std::ios_base& ios_obj, int index)
{
...
if (std::ostream& os = dynamic_cast<std::ostream&>(ios_obj)) {
uninstall_log_streambuf(os, index);
}
else if (std::wostream& os = dynamic_cast<std::wostream&>(ios_obj)) {
uninstall_log_streambuf(os, index);
}
else
{
throw std::runtime_error("scm::log::indent::callback() runtime error, failed to dynamic_cast ios_obj.");
}
...
}
|
Wenn ein dynamic cast für ein Referenzobjekt schief geht wird eine std::bad_cast exception ausgelöst.
Dagegen liefert der Aufruf eines dynamic cast für einen Pointers NULL wenn die Konvertierung nicht möglich ist.
Der Test für das std::wostream& Objekt wird also nie erreicht. Für eine ernsthafte Implementierung würde ich die
Callback-Funktion als template-funktion registrieren. Die Fallunterscheidung fällt dann natürlich weg.
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 | 1 2 3 4 5 6 7 8 9 10 11 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
//...
typedef std::basic_ostream<char_type,traits> basic_ostream;
if(basic_ostream * os = dynamic_cast<basic_ostream *>(&ios_obj))
{
uninstall_log_streambuf(*os, index);
}
//...
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
//...
typedef std::basic_ostream<char_type,traits> basic_ostream;
if(basic_ostream * os = dynamic_cast<basic_ostream *>(&ios_obj))
{
uninstall_log_streambuf(*os, index);
}
//...
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
//...
typedef std::basic_ostream<char_type,traits> basic_ostream;
if(basic_ostream * os = dynamic_cast<basic_ostream *>(&ios_obj))
{
uninstall_log_streambuf(*os, index);
}
//...
}
| |
Bei mir wurde übrigens eine bad_cast Exeption beim Lösch-Event ausgelöst.
Ich habe inzwischen noch eine alternative Implementierung die auch funktionieren müsste.
Da der cast beim Löschen schief ging, habe ich den ostream einfach in pword gespeichert.
In der ersten if-Abfrage prüfe ich ob schon ein indent buffer Objekt existiert. Wenn ja
wird natürlich kein neuer Speicher reserviert und ein Null-Pointer zurückgegeben.
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | 1 2 3 4 5 6 7 8 9 10 11 12 | template <typename char_type, typename traits>
inline format::indentbuf* install_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * test = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
return NULL;
}
format::indentbuf* sbuf(new format::indentbuf(o_s.rdbuf()));
o_s.rdbuf(sbuf);
o_s.pword(indent_index) = &o_s;
return sbuf;
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | template <typename char_type, typename traits>
inline format::indentbuf* install_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * test = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
return NULL;
}
format::indentbuf* sbuf(new format::indentbuf(o_s.rdbuf()));
o_s.rdbuf(sbuf);
o_s.pword(indent_index) = &o_s;
return sbuf;
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | template <typename char_type, typename traits>
inline format::indentbuf* install_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * test = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
return NULL;
}
format::indentbuf* sbuf(new format::indentbuf(o_s.rdbuf()));
o_s.rdbuf(sbuf);
o_s.pword(indent_index) = &o_s;
return sbuf;
}
| |
Die uninstall Funktion überprüft das Objekt vor dem Löschen.
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 | 1 2 3 4 5 6 7 8 9 10 | template <typename char_type, typename traits>
inline void uninstall_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * sbuf = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
delete sbuf;
o_s.pword(indent_index) = 0;
o_s.rdbuf(0);
}
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 | template <typename char_type, typename traits>
inline void uninstall_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * sbuf = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
delete sbuf;
o_s.pword(indent_index) = 0;
o_s.rdbuf(0);
}
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 | template <typename char_type, typename traits>
inline void uninstall_buffer(std::basic_ostream<char_type, traits> & o_s)
{
if(format::indentbuf * sbuf = dynamic_cast<format::indentbuf *>(o_s.rdbuf()))
{
delete sbuf;
o_s.pword(indent_index) = 0;
o_s.rdbuf(0);
}
}
| |
Das ist sinnvoll weil der Übergabeparameter per static_cast nicht typsicher konvertiert werden kann.
Beim Copy-Event wird nur bei Bedarf Speicher alloziert.
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
typedef std::basic_ostream<char_type,traits> basic_ostream;
if (ev == std::ios_base::erase_event)
{
basic_ostream * bos = static_cast<basic_ostream *>(static_cast<basic_ostream *>(ios.pword(index)));
if(bos)
{
uninstall_buffer<char_type,traits>(*bos);
}
}
else if(ev == std::ios_base::copyfmt_event)
{
if(std::ostream * o_s = dynamic_cast<std::ostream *>(&ios)) // avoid bad cast exception
{
*o_s << format::indent(get_indent(ios));
}
}
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
typedef std::basic_ostream<char_type,traits> basic_ostream;
if (ev == std::ios_base::erase_event)
{
basic_ostream * bos = static_cast<basic_ostream *>(static_cast<basic_ostream *>(ios.pword(index)));
if(bos)
{
uninstall_buffer<char_type,traits>(*bos);
}
}
else if(ev == std::ios_base::copyfmt_event)
{
if(std::ostream * o_s = dynamic_cast<std::ostream *>(&ios)) // avoid bad cast exception
{
*o_s << format::indent(get_indent(ios));
}
}
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template <typename char_type, typename traits>
inline void callback(std::ios_base::event ev, std::ios_base& ios, int index)
{
typedef std::basic_ostream<char_type,traits> basic_ostream;
if (ev == std::ios_base::erase_event)
{
basic_ostream * bos = static_cast<basic_ostream *>(static_cast<basic_ostream *>(ios.pword(index)));
if(bos)
{
uninstall_buffer<char_type,traits>(*bos);
}
}
else if(ev == std::ios_base::copyfmt_event)
{
if(std::ostream * o_s = dynamic_cast<std::ostream *>(&ios)) // avoid bad cast exception
{
*o_s << format::indent(get_indent(ios));
}
}
}
| |
Den inserter habe ich jetzt wie folgt definiert
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template <typename char_type, typename traits>
inline std::ostream& operator<< (std::basic_ostream<char_type,traits> & o_s, format::indent const& ind)
{
format::indentbuf* sbuf = dynamic_cast<format::indentbuf*>(o_s.rdbuf()); //stream pointer lesen
if(!sbuf) //wenn streambuffer pointer noch nicht exitstiert
{
sbuf = install_buffer(o_s);
if(sbuf)
{
o_s.register_callback(callback<char_type,traits>, indent_index);
}
}
set_indent(o_s,ind.indent_);
sbuf->indent(ind.indent_); //indent spacing setzen
return o_s;
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template <typename char_type, typename traits>
inline std::ostream& operator<< (std::basic_ostream<char_type,traits> & o_s, format::indent const& ind)
{
format::indentbuf* sbuf = dynamic_cast<format::indentbuf*>(o_s.rdbuf()); //stream pointer lesen
if(!sbuf) //wenn streambuffer pointer noch nicht exitstiert
{
sbuf = install_buffer(o_s);
if(sbuf)
{
o_s.register_callback(callback<char_type,traits>, indent_index);
}
}
set_indent(o_s,ind.indent_);
sbuf->indent(ind.indent_); //indent spacing setzen
return o_s;
}
| |
| C/C++ Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template <typename char_type, typename traits>
inline std::ostream& operator<< (std::basic_ostream<char_type,traits> & o_s, format::indent const& ind)
{
format::indentbuf* sbuf = dynamic_cast<format::indentbuf*>(o_s.rdbuf()); //stream pointer lesen
if(!sbuf) //wenn streambuffer pointer noch nicht exitstiert
{
sbuf = install_buffer(o_s);
if(sbuf)
{
o_s.register_callback(callback<char_type,traits>, indent_index);
}
}
set_indent(o_s,ind.indent_);
sbuf->indent(ind.indent_); //indent spacing setzen
return o_s;
}
| |
| Chris Lux schrieb: |
Was meinst du dazu?
P.S. Das seltsamste was mir seit langem untergekommen ist: Ich gehe das Ganze im Debugger Schritt für Schritt durch und in der install_log_streambuf Methode erhalte ich einen Fehler beider letzten Assertion:
| C/C++ Code: | log_streambuf_type* log_rdbuf = new log_streambuf_type(os.rdbuf());
os.rdbuf(log_rdbuf);
os.pword(index) = log_rdbuf;
assert(log_rdbuf == os.rdbuf());
assert(log_rdbuf == os.pword(index));
assert(os.pword(index) == os.rdbuf());
| |
| C/C++ Code: | log_streambuf_type* log_rdbuf = new log_streambuf_type(os.rdbuf());
os.rdbuf(log_rdbuf);
os.pword(index) = log_rdbuf;
assert(log_rdbuf == os.rdbuf());
assert(log_rdbuf == os.pword(index));
assert(os.pword(index) == os.rdbuf());
| |
| C/C++ Code: | log_streambuf_type* log_rdbuf = new log_streambuf_type(os.rdbuf());
os.rdbuf(log_rdbuf);
os.pword(index) = log_rdbuf;
assert(log_rdbuf == os.rdbuf());
assert(log_rdbuf == os.pword(index));
assert(os.pword(index) == os.rdbuf());
| |
|
Wenn A == C und B == C, dann ist hier A != B. Das ist natürlich nicht ganz so intuitiv.
rdbuf gibt ein ios_base Objekt zurück, das nach void* konvertiert wird.
Die ios_base Klasse hat den void * Konvertierungs-Operator implementiert.
| C/C++ Code: | operator void *() const;
{
// assert(sizeof(this) == sizeof(void*)); // ???
}
| |
| C/C++ Code: | operator void *() const;
{
// assert(sizeof(this) == sizeof(void*)); // ???
}
| |
| C/C++ Code: | operator void *() const;
{
// assert(sizeof(this) == sizeof(void*)); // ???
}
| |
Mit besten Grüßen
Erik |
_________________ Erik Griessmann
Zuletzt bearbeitet von rik am 13:48:36 12.02.2010, insgesamt 1-mal bearbeitet |
|