expertenaustausch > comp.lang.* > comp.lang.iso-c++

Udo Steinbach (14.12.2018, 19:32)
Wie paßt
csv_whitespace* my_ws = new csv_whitespace; // note: this allocation is not leaked
auf zusammen damit, das der
Konstruktor werfen kann und es auch tut, gleich als erstes:
template<typename _Facet> locale::locale(const locale& __other, _Facet* __f)
{ _M_impl = new _Impl(*__other._M_impl, 1);
__try { ...

Wenn new _Impl wirft, ist doch __f bzw. my_ws verloren, oder sehe ich den
Wald vor lauter Bäumen nicht? Es ist anscheinend kein Fehler im Beispiel,
der Konstruktor soll mit (source, new MyFacet) benutzt werden.

Bei LLVM siehts ähnlich aus, Konstruktor ruft auf
void locale::__install_ctor(const locale& other, facet* f, long id)
{ if (f)
__locale_ = new __imp(*other.__locale_, f, id);
else
Stefan Ram (15.12.2018, 06:39)
Udo Steinbach <trashcan> 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(); }
Udo Steinbach (16.12.2018, 23:45)
Am 2018-12-15 um 05:39 schrieb Stefan Ram:
> Ich habe hierzu ein Programm (Quelltext folgt unten) geschrieben.


Das lob' ich mir! Es zeigt, was ich erwartet habe. Ersetzen durch
auto my_ws= std::make_unique<csv_whitespace>(); , mit my_ws.reset();
natürlich, macht alles richtig. Dieses Verhalten des Konstruktors scheint
mir logisch zwecks Unabhängigkeit der storage-class von Facet, und nach der
Bestimmung , denn bei einem werfenden
locale()-Konstruktor ist Facet ja nicht Teil des locale.
Ähnliche Themen