Udo Steinbach <
tras...@udoline.de> writes:
>Wenn new _Impl wirft, ist doch __f bzw. my_ws verloren, oder sehe ich den
>Wald vor lauter Bäumen nicht?
Ich habe hierzu ein Programm (Quelltext folgt unten) geschrieben.
Es kann (hier unter einem relativ aktuellen GCC) simulieren,
daß »new _Impl« »bad_alloc« wirft. (Ich weiß nicht, wie
portabel es ist!)
Wenn man es nicht werfen läßt, so lautet die Ausgabe:
|now will allocate facet with new
|new 736 bytes at 0x108a248
|now will create new locale with facet
|sized delete 736 bytes at 0x108a248
|closing
|closed
|Everything ok, no memory leak!
Die Facette wurde beim Auflösen des letzten sie enthaltenden
Schauplatzes mit aufgelöst.
Nun wird das Werfen simuliert:
|now will allocate facet with new
|new 736 bytes at 0xdac948
|now will create new locale with facet
|throwing
|Caught bad_alloc.
|Oh no! memory leak detected!
Mögliche Umgehung:
, Als Argument für den refs-Parameter des Konstruktors
der Standardklasse "facet" immer 1 zu verwenden.
Dadurch wird das automatische Auflösen unterdrückt und man
kann den Speicher dann manuell verwalten, eventuell auch
mit Hilfe von Schlauzeigern. (Diese Verwaltung könnte aber
unter Umständen unübersichtlich werden.)
(Der folgende Quelltext enthält auch einige lange Zeilen mit
bis zu 103 Zeichen. Ich hoffe, daß diese nicht nach dem
Versand umbrochen werden.)
#include <iostream>
#include <locale>
#include <sstream>
#include <new>
int trace = 0; /* is this the allocation of the facet to trace? */
/* DO NOT change "trace" here, but only in main1, directly before the allocation! */
void * tmem = nullptr; /* the address of the facet allocated */
int bad = 0; /* do we want to simulate a bad_alloc? */
/* DO NOT change "bad" here, but only in main1, directly before the allocation! */
void *operator new(size_t size)
{ if( bad ){ bad=0; ::std::cout << "throwing\n"; throw ::std::bad_alloc{}; }
auto mem = malloc(size);
if( trace ){ ::std::cout << "new " << size << " bytes at " << mem << '\n'; tmem = mem; trace = 0; }
return mem; }
void operator delete( void* ptr )
{ if( ptr==tmem )::std::cout << "delete at " << ptr << '\n';
free( ptr ); }
void operator delete(void*ptr, std::size_t s)
{ if( ptr==tmem )::std::cout << "sized delete " << s << " bytes at " << ptr << '\n';
free( ptr );
if( ptr == tmem )tmem = nullptr; /* ok, it did NOT leak */ }
void check()
{ ::std::cout << (tmem?"Oh no! memory leak detected!\n":"Everything ok, no memory leak!\n"); }
struct csv_whitespace : std::ctype<wchar_t>{};
void main1()
{ { ::std::istringstream iss( "" );
::std::cout << "now will allocate facet with new" << '\n';
trace = 1; /* trace the next allocation */
auto * my_ws = new csv_whitespace; /* is this allocation leaked? */
std::cout << "now will create new locale with facet" << '\n';
bad = 1; /* simulate out-of-memory condition by throwing bad_alloc */
std::locale( iss.getloc(), my_ws );
std::cout << "closing\n"; }
std::cout << "closed\n"; }
int main()
{ try{ main1(); }
catch( ::std::bad_alloc& ba ){ ::std::cout << "Caught bad_alloc.\n"; }
check(); }