Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Die Artikel ::  Benutzerdefinierte Manipulatoren  
Gehen Sie zu Seite Zurück  1, 2
  Zeige alle Beiträge auf einer Seite
Auf Beitrag antworten
Autor Nachricht
rik
Autor

Benutzerprofil
Anmeldungsdatum: 18.05.2006
Beiträge: 36
Beitrag 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
C/C++ Forum :: Die Artikel ::  Benutzerdefinierte Manipulatoren  
Gehen Sie zu Seite Zurück  1, 2
Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.