C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

placment new/delete

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Daniel Schüle
Guest





PostPosted: Sat Mar 26, 2005 2:24 am    Post subject: placment new/delete Reply with quote



Hallo NG

Ich habe 3 Fragen, die aus dem unten angegebenem Code bei
mir aufkommen.

1) ist die "new" Version
void * new(size_t size, char * buf);
immer bei C++ "dabei"?

2) wie lösche ich die erzeugten Objekten richtig?
mit "delete" werden die Destruktoren zwar aufgerufen, aber
erzeuge ich kein undefeniertes Verhalten?
Insbesondere bei
void * new(size_t size, Allocator & a);
returne ich malloc() .. es wäre aber sicher auch denkbar
einen Zeiger zB auf anderen Bereich zurückzugeben.
Das würde doch sicher Probleme mit dem normalen "delete" ergeben?
Oder darf einfaches "delete" immer an Zeiger angewendet werden,
die im "new" malloc benutzt haben?

3) unter
http://www.glenmccl.com/nd_cmp.htm
habe ich einen placement delete entdeckt
delete (MyAlloc) f;
hat nicht funktioniert .. was laut
"Placement delete may not be in your local C++ compiler as yet."
nicht so überraschend war.
Allerdings sollte dieses placement delete, (wie dort beschrieben)
nur aufgerufen werden, wenn bei im "new" eine Ausnahme geworfen wird.
D.h es dürfte dann gar nicht mit
delete (MyAlloc) f;
aufgerufen werden.
Obwohl es logischer wäre, zumindenst meiner Meineung nach,
dies zu zulassen. Damit zu jedem
foo * f = new(MyAloc) foo;
ein
delete (MyAlloc)f;
gehört.

Falls jemand gute Onlinequellen dazu kennt und mich mit Links
versorgt, wäre ich sehr dankbar.

Dank im Voraus

-Daniel



#include <iostream>
#include <cstdlib>

using std::cout;
using std::endl;

class Allocator
{
public:
Allocator() : cnt(0) {}
void inc(size_t size) { cnt += size; }
size_t get()const { return cnt; }
private:
size_t cnt;
}MyAlloc;

void * operator new(size_t size, Allocator & a)
{
cout << "new" << endl;
a.inc(size);
return malloc(size);
}

struct foo
{
foo() :i(0xff00ff00), f(0.0) { cout << "foo" << endl; }
~foo() { cout << "~foo" << endl; }
unsigned int i;
};

void alloc()
{
foo * f = new(MyAlloc) foo;
cout << f->i << endl;
delete f; // *hier*

char buffer[1024];
f = new(buffer) foo();
delete f; // *hier auch*
}

int main()
{
alloc();
cout << "Alloc = " << MyAlloc.get() << endl;
}

--
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





PostPosted: Sat Mar 26, 2005 8:57 am    Post subject: Re: placment new/delete Reply with quote



Daniel Schüle <uval (AT) rz (DOT) uni-karlsruhe.de> writes:

Quote:
Ich habe 3 Fragen, die aus dem unten angegebenem Code bei
mir aufkommen.

1) ist die "new" Version void * new(size_t size, char * buf); immer
bei C++ "dabei"?

Nein.

Die placement new-Operator, welche immer dabei sind, sind:

void * operator new(size_t size, void *) throw();
void * operator new[](size_t size, void *) throw();


Quote:
2) wie lösche ich die erzeugten Objekten richtig? mit "delete"
werden die Destruktoren zwar aufgerufen, aber erzeuge ich kein
undefeniertes Verhalten?

Nein. Du erzeugst undefiniertes Verhalten.

Du must den Destruktor explizit aufrufen. Wenn wir also annehmen, dass
memory auf einen Speicherbereich mit passender Grösse und passendem
Alignment zeigt:

struct S {};
S *s = new (memory) S;
s->~S();


Quote:
Insbesondere bei
void * new(size_t size, Allocator & a);
returne ich malloc() .. es wäre aber sicher auch denkbar
einen Zeiger zB auf anderen Bereich zurückzugeben.
Das würde doch sicher Probleme mit dem normalen "delete" ergeben?

Würde es, ja.


Quote:
Oder darf einfaches "delete" immer an Zeiger angewendet werden, die
im "new" malloc benutzt haben?

Nein.


Quote:
3) unter http://www.glenmccl.com/nd_cmp.htm habe ich einen placement
delete entdeckt

delete (MyAlloc) f;

hat nicht funktioniert .. was laut "Placement delete may not be in
your local C++ compiler as yet." nicht so überraschend
war. Allerdings sollte dieses placement delete, (wie dort
beschrieben) nur aufgerufen werden, wenn bei im "new" eine Ausnahme
geworfen wird.

Letzteres wird wohl der wahre Grund gewesen sein, warum der oben
angegebene delete-Ausdruck nicht ausgewertet werden kann.

--
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 Mang
Guest





PostPosted: Sat Mar 26, 2005 9:48 am    Post subject: Re: placment new/delete Reply with quote




"Daniel Schüle" <uval (AT) rz (DOT) uni-karlsruhe.de> schrieb im Newsbeitrag
news:d22h5j$1hf$1 (AT) news2 (DOT) rz.uni-karlsruhe.de...
Quote:
Hallo NG

Ich habe 3 Fragen, die aus dem unten angegebenem Code bei
mir aufkommen.

1) ist die "new" Version
void * new(size_t size, char * buf);
immer bei C++ "dabei"?


Nein


Quote:

2) wie lösche ich die erzeugten Objekten richtig?
mit "delete" werden die Destruktoren zwar aufgerufen, aber
erzeuge ich kein undefeniertes Verhalten?


Ja, undefinierters Verhalten.


Quote:
Insbesondere bei
void * new(size_t size, Allocator & a);
returne ich malloc() .. es wäre aber sicher auch denkbar
einen Zeiger zB auf anderen Bereich zurückzugeben.
Das würde doch sicher Probleme mit dem normalen "delete" ergeben?
Oder darf einfaches "delete" immer an Zeiger angewendet werden,
die im "new" malloc benutzt haben?


Nein


Quote:

3) unter
http://www.glenmccl.com/nd_cmp.htm
habe ich einen placement delete entdeckt
delete (MyAlloc) f;
hat nicht funktioniert .. was laut
"Placement delete may not be in your local C++ compiler as yet."
nicht so überraschend war.


es gibt kein placement delete oder sowas, weil die Syntax lautet:

delete cast-expression


Quote:
Allerdings sollte dieses placement delete, (wie dort beschrieben)
nur aufgerufen werden, wenn bei im "new" eine Ausnahme geworfen wird.


Ja, zu einem selbst gebastelten new braucht man im Falle von exceptions auch
ein korrespondierendes delete, daß aufgerufen wird wenn bei der Konstruktion
des Objektes eine exception geworfen wird, um Speicherlecks zu verhindern.


Quote:
D.h es dürfte dann gar nicht mit
delete (MyAlloc) f;
aufgerufen werden.
Obwohl es logischer wäre, zumindenst meiner Meineung nach,
dies zu zulassen. Damit zu jedem
foo * f = new(MyAloc) foo;
ein
delete (MyAlloc)f;
gehört.


Ja, so ein delete gibt es nicht. Im Prinzip kann eine expression mit Klammer
vor dem zu löschenden Objekt gültig sein, wenn es eine gültige
cast-expression ist:

int * i = 0;
delete (double*) i;

Logischerweise Hände weg davon!


Quote:

Falls jemand gute Onlinequellen dazu kennt und mich mit Links
versorgt, wäre ich sehr dankbar.

Dank im Voraus

-Daniel



#include <iostream
#include
using std::cout;
using std::endl;

class Allocator
{
public:
Allocator() : cnt(0) {}
void inc(size_t size) { cnt += size; }
size_t get()const { return cnt; }
private:
size_t cnt;
}MyAlloc;

void * operator new(size_t size, Allocator & a)
{
cout << "new" << endl;
a.inc(size);
return malloc(size);
}

struct foo
{
foo() :i(0xff00ff00), f(0.0) { cout << "foo" << endl; }
~foo() { cout << "~foo" << endl; }
unsigned int i;
};

void alloc()
{
foo * f = new(MyAlloc) foo;
cout << f->i << endl;
delete f; // *hier*


undefinierters Verhalten


Quote:

char buffer[1024];
f = new(buffer) foo();


Ich kenne void* operator new(std::size_t, char*) nicht, aber wenn der eine
Art placement-new ist, ist hier das Verhalten wegen alignment ebenfalls
undefiniert.

Quote:
delete f; // *hier auch*


Prinzipiell gilt es einmal zu wissen, was eine new/delete - expression
macht, und ein operator new /delete.

Ein operator new stellt lediglich Speicher für ein Objekt bereit, und zwar
mit dem entsprechenden alignment. Ein operator delete gibt nur diesen
Rohspeicher wieder frei.
Eine new-expression macht 2 Dinge: Sie alloziiert zuerst Rohspeicher (über
operator new), und konstruiert dann innerhalb dieses Rohspeichers ein neues
Objekt. Eine delete-expression ruft zuerst den Destruktor des Objektes auf,
und löscht dann den Rohspeicher mit einem Aufruf nach operator delete. Bei
einer new-expression kann man nun, wie Du bereits weißt, den aufzurufenden
operator new steuern, indem man zusätzliche Argumente übergibt. Bei einer
delete-expression geht das nicht, da wird der standardmäßig vorhandene
operator delete(void*) aufgerufen. Für ein ordentliches Programm muß pro
operator new auch der operator delete übereinstimmen (semantisch; Speicher
ordentlich wieder befreit, auf welche Art auch immer). Bei Dir bräuchte man
zuerst einmal das zum new dazugehörende delete:

void * operator new(std::size_t s, Allocator& a)
{
a.Allocating();
return std::malloc(s);
}

void operator delete(void* p, Allocator& a)
{
a.Deallocating();
std::free(p); // free ist das pendant zu malloc !
}


In main kann man dann bei der new-expression automatisch den operator new
auswählen, den delete muß man manuell aufrufen:

int main()
{
Allocator a;
Foo * f = new (a) Foo;

// nun zuerst Objekt zerstören:
f->~Foo();

// und dann Speicher freigeben:
::operator delete(f, a);
}



Zu beachten ist, daß die normale delete expression verwendet werden kann,
wenn der operator delete innerhalb einer Klasse überladen ist, und eine von
diesen Formen annimmt:

struct Test
{
void operator delete(void*);
void operator delete(void*, std::size_t);
};

weil der dann ganz normal gefunden/aufgerufen wird.



Generell empfehle ich Dir bei zusätzlichen Argumenten an operator new /
delete die Speicheralloziierung von der Objektkonstruktion zu trennen.
Das heißt obiges Programm würde ich so schreiben:

// Speicher
void* Mem = ::operator new(sizeof(Foo), a);

// Objekt konstruieren
Foo* f = ::new (Mem) foo;


// Objekt zerstören
f->~Foo();
// Speicher freigeben
::operator delete(Mem, a);


Das alles kann man natürlich auch in hübsche template-Funktionen packen, die
alles kapseln:

template <typename T>
T* createHeapT(Allocator & a)
{
wie oben
}


template <typename T>
void deleteHeapT(T* t, Allocator& a)
{
wie oben
}


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
Daniel Schüle
Guest





PostPosted: Sat Mar 26, 2005 10:44 am    Post subject: Re: placment new/delete Reply with quote

Hallo Thomas,

Quote:
Die placement new-Operator, welche immer dabei sind, sind:

void * operator new(size_t size, void *) throw();
void * operator new[](size_t size, void *) throw();

struct foo{};
char buffer[1024];
foo * f = new(buffer) foo();

Jetzt ist klar, hier wird also char * nach void* implizit konvertiert.

[...]

Quote:
Du must den Destruktor explizit aufrufen. Wenn wir also annehmen, dass
memory auf einen Speicherbereich mit passender Grösse und passendem
Alignment zeigt:

struct S {};
S *s = new (memory) S;
s->~S();

struct foo
{
foo(int size) : pi(new int[size]) {}
~foo() { delete [] pi; }
int * pi;
};

class Allocator
{
public:
Allocator() : cnt(0) {}
void inc(size_t size) { cnt += size; }
size_t get()const { return cnt; }
private:
size_t cnt;
}MyAlloc;

void * operator new(size_t size, Allocator & a)
{
cout << "new" << endl;
a.inc(size);
return malloc(size);
}

int main()
{
foo * f = new(MyAlloc) foo(10000);
f->~foo(); // *1*
}

Bei *1* wird der Destructor für f aufgerufen und pi
(und andere Ressourcen von f) werden freigegeben,
aber f selber ist ja mit malloc allokiert. (Und liegt auf dem Heap)
Würde also Speicherplatz für f damit auch freigegeben?
Immerhin ist kein Aufruf von free zu sehen.

MfG

-Daniel

--
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





PostPosted: Sat Mar 26, 2005 12:56 pm    Post subject: Re: placment new/delete Reply with quote

Daniel Schüle <uval (AT) rz (DOT) uni-karlsruhe.de> writes:

Quote:
struct foo{};
char buffer[1024];
foo * f = new(buffer) foo();

Bist Du sicher, dass buffer korrekt aligned ist?


Quote:
struct foo
{
foo(int size) : pi(new int[size]) {}
~foo() { delete [] pi; }
int * pi;
};

Was spricht dagegen, stattdessen boost::scoped_array<int> zu verwenden?


Quote:
class Allocator
{
public:
Allocator() : cnt(0) {}
void inc(size_t size) { cnt += size; }
size_t get()const { return cnt; }
private:
size_t cnt;
}MyAlloc;

Der Name Allocator ist hier falsch verwendet. Das ist ja kein
Allozierer, sondern bloss ein Allozierungszähler.


Quote:
void * operator new(size_t size, Allocator & a)
{
cout << "new" << endl;
a.inc(size);
return malloc(size);
}

int main()
{
foo * f = new(MyAlloc) foo(10000);
f->~foo(); // *1*
}

Bei *1* wird der Destructor für f aufgerufen und pi
(und andere Ressourcen von f) werden freigegeben,
aber f selber ist ja mit malloc allokiert. (Und liegt auf dem Heap)
Würde also Speicherplatz für f damit auch freigegeben?
Immerhin ist kein Aufruf von free zu sehen.

Nein, der Speicherplatz geht hier verloren.

Der direkte Aufruf des Destruktors ist nur für Objekte sinnvoll,
welche wörtlichen mit placement new konstruiert wurden.


new(MyAlloc) foo(10000)

hat zwar eine ähnliche Syntax, aber mit dem Placement des neuen
Objekts hat das Argument MyAlloc im Allgemeinen nichts zu tun.


Mir scheint, dass Du in Deinem Anwendungsfall den operator new() eher
in der Klasse foo überladen solltest. Das liegt aber vielleicht daran,
dass ich zuwenig darüber weiss, was Du tun willst.

--
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
Daniel Schüle
Guest





PostPosted: Sat Mar 26, 2005 2:10 pm    Post subject: Re: placment new/delete Reply with quote

[...]

Quote:
struct foo{};
char buffer[1024];
foo * f = new(buffer) foo();


Bist Du sicher, dass buffer korrekt aligned ist?

Du meinst, dass auf manchen Systemen Objekte zu bestimmten
Speichergrenzen alignet werden und es zu Problemen führt,
wenn zB buffer auf 4 Byte Grenze ausgerichtet ist und Instanzen von foo
auf 16 byte Grenze liegen möchten?
In diesem Sinne bin mir nicht sicher, dass es korrekt aligned ist.
Ich habe gerade ausprobiert, das geht wahrscheinlich nur
Compilerabhängig und geht bei MinGW

struct foo
{
int i;
double d;
char name[11];
};

int main()
{
typedef char kBuffer[1024] __attribute__((aligned(512)));
cout << "alignof(buffer) = " << __alignof__(kBuffer) << endl;
cout << "alignof(foo) = " << __alignof__(foo) << endl;
}

Das heisst man müsste auf jeden Fall prüfen, dass
__alignof__(foo) <= __alignof__(buffer), richtig?


[...]


Quote:
Was spricht dagegen, stattdessen boost::scoped_array

Mit boost kenne ich mich nicht gut aus.
Ich habe es runtergeladen, konnte es aber nicht build-en.
Und eine binary Version mit *.hpp, *.dll, *.lib habe ich nicht gefunden.

Quote:
class Allocator
{
public:
Allocator() : cnt(0) {}
void inc(size_t size) { cnt += size; }
size_t get()const { return cnt; }
private:
size_t cnt;
}MyAlloc;


Der Name Allocator ist hier falsch verwendet. Das ist ja kein
Allozierer, sondern bloss ein Allozierungszähler.

Ja, das stimmt, der Name ist irreführend.
Es war auch nur als ein kleines Testprogram gedacht,
die richtige Benutzung von placement new/delete anzuschauen.

[...]


Quote:
Der direkte Aufruf des Destruktors ist nur für Objekte sinnvoll,
welche wörtlichen mit placement new konstruiert wurden.

mit wörtlichem placement new konstruiert?
ich verstehe nicht ganz was du meinst

[...]

Quote:
Mir scheint, dass Du in Deinem Anwendungsfall den operator new() eher
in der Klasse foo überladen solltest. Das liegt aber vielleicht daran,
dass ich zuwenig darüber weiss, was Du tun willst.

Das wollte ich auch noch später anschauen :)

Gruss Daniel

--
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





PostPosted: Sat Mar 26, 2005 4:54 pm    Post subject: Re: placment new/delete Reply with quote

Daniel Schüle <uval (AT) rz (DOT) uni-karlsruhe.de> writes:

Quote:
Bist Du sicher, dass buffer korrekt aligned ist?

Du meinst, dass auf manchen Systemen Objekte zu bestimmten
Speichergrenzen alignet werden und es zu Problemen führt,
wenn zB buffer auf 4 Byte Grenze ausgerichtet ist und Instanzen von
foo auf 16 byte Grenze liegen möchten?

Genau.

Das Resultat von Funktionen wie malloc() und ::operator new() ist
garantiert korrekt aligned für jeden Datentyp. Ein x-beliebies
char-Array von automatischer oder statischer Lebensdauer aber nicht.


Quote:
In diesem Sinne bin mir nicht sicher, dass es korrekt aligned ist.
Ich habe gerade ausprobiert, das geht wahrscheinlich nur
Compilerabhängig und geht bei MinGW

struct foo
{
int i;
double d;
char name[11];
};

int main()
{
typedef char kBuffer[1024] __attribute__((aligned(512)));
cout << "alignof(buffer) = " << __alignof__(kBuffer) << endl;
cout << "alignof(foo) = " << __alignof__(foo) << endl;
}

Das heisst man müsste auf jeden Fall prüfen, dass
__alignof__(foo) <= __alignof__(buffer), richtig?

Kann sein. Ich kenne __alignof__ nicht.


Quote:
Was spricht dagegen, stattdessen boost::scoped_array
Mit boost kenne ich mich nicht gut aus.
Ich habe es runtergeladen, konnte es aber nicht build-en.
Und eine binary Version mit *.hpp, *.dll, *.lib habe ich nicht gefunden.

Meiner Erfahrung nach ist die Installationsdokumentation der
Boost-Bibliotheken exzellent.


Quote:
Der direkte Aufruf des Destruktors ist nur für Objekte sinnvoll,
welche wörtlichen mit placement new konstruiert wurden.

mit wörtlichem placement new konstruiert?
ich verstehe nicht ganz was du meinst

Dort, wo placement new für die Plazierung des Objekts im Speicher
verwendet wird.

--
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





PostPosted: Sat Mar 26, 2005 5:37 pm    Post subject: Re: placment new/delete Reply with quote

Daniel Schüle wrote:

Quote:
[...]

struct foo{};
char buffer[1024];
foo * f = new(buffer) foo();


Bist Du sicher, dass buffer korrekt aligned ist?

Du meinst, dass auf manchen Systemen Objekte zu bestimmten
Speichergrenzen alignet werden und es zu Problemen führt,
wenn zB buffer auf 4 Byte Grenze ausgerichtet ist und Instanzen von foo
auf 16 byte Grenze liegen möchten?

Vermutlich meint er das. Wobei ein lokales Array aus char auch evtl. auch
gar kein Alignment haben, also an jeder beliebigen Adresse anfangen könnte.

Quote:
In diesem Sinne bin mir nicht sicher, dass es korrekt aligned ist.
Ich habe gerade ausprobiert, das geht wahrscheinlich nur
Compilerabhängig und geht bei MinGW

Es ist nicht nur compilerabhängig, sondern auch hardwareabhängig. Auf
einigen Systemen ist ein Zugriff ohne korrektes Alignment gar nicht
möglich. Auf anderen (z.B. x86) schon, aber mit Laufzeitoverhead.

Quote:
struct foo
{
int i;
double d;
char name[11];
};

int main()
{
typedef char kBuffer[1024] __attribute__((aligned(512)));
cout << "alignof(buffer) = " << __alignof__(kBuffer) << endl;
cout << "alignof(foo) = " << __alignof__(foo) << endl;
}

Das heisst man müsste auf jeden Fall prüfen, dass
__alignof__(foo) <= __alignof__(buffer), richtig?

Falls ich die Funktion von __alignof__ richtig verstehe, ja.

Quote:

[...]


Was spricht dagegen, stattdessen boost::scoped_array
Mit boost kenne ich mich nicht gut aus.
Ich habe es runtergeladen, konnte es aber nicht build-en.

Die meisten Teile von Boost brauchen gar keine extra-Bibliothek. #includen
der Header reicht.

--
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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.