 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Markus Moll Guest
|
Posted: Fri Mar 03, 2006 4:06 pm Post subject: uninitialized_copy |
|
|
Hallo
Mal angenommen, ich habe eine Klasse (T), deren Objekte _wirklich_ teuer zu
konstruieren sind, oder eine, die keinen Default-Konstruktor besitzt.
Jetzt möchte ich eine Kopie eines Arrays von T anlegen.
Ich dachte daran, rohen Speicher mit T* arr = std::operator new[](n *
sizeof(T)) anzufordern, und dann per std::uninitialized_copy(orig, orig+n,
arr) das Originalarray orig hineinzukonstruieren.
Allerdings frage ich mich nun: Ist der einzig korrekte Weg, das ganze
rückgängig zu machen, über arr zu iterieren, auf jedem Objekt einen
Pseudodestruktoraufruf zu machen und den Speicher mit std::operator
delete[](arr) wieder freizugeben?
Ich dachte ursprünglich, ich könne einfach delete[] arr; benutzen, aber das
ist wohl undefiniert (da arr nicht mit new[] erzeugt wurde).
Gruß
Markus
--
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 |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Mar 03, 2006 6:06 pm Post subject: Re: uninitialized_copy |
|
|
Markus Moll wrote:
| Quote: | Jetzt möchte ich eine Kopie eines Arrays von T anlegen.
Ich dachte daran, rohen Speicher mit T* arr = std::operator new[](n *
sizeof(T)) anzufordern, und dann per std::uninitialized_copy(orig, orig+n,
arr) das Originalarray orig hineinzukonstruieren.
|
Warum eigentlich nicht
std::vector<T> arr(orig, orig+n);
?
| Quote: | Allerdings frage ich mich nun: Ist der einzig korrekte Weg, das ganze
rückgängig zu machen, über arr zu iterieren, auf jedem Objekt einen
Pseudodestruktoraufruf zu machen und den Speicher mit std::operator
delete[](arr) wieder freizugeben?
Ich dachte ursprünglich, ich könne einfach delete[] arr; benutzen, aber das
ist wohl undefiniert (da arr nicht mit new[] erzeugt wurde).
|
.... und demzufolge die Anzahl `n' der aufzurufenden Destruktoren
nicht dort auffindbar ist, wo es für das delete[] erwartet wird.
MfG
Falk
--
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 |
|
 |
Christoph Bartoschek Guest
|
Posted: Fri Mar 03, 2006 9:06 pm Post subject: Re: uninitialized_copy |
|
|
Markus Moll wrote:
| Quote: | Mal angenommen, ich habe eine Klasse (T), deren Objekte wirklich teuer
zu konstruieren sind, oder eine, die keinen Default-Konstruktor besitzt.
Jetzt möchte ich eine Kopie eines Arrays von T anlegen.
Ich dachte daran, rohen Speicher mit T* arr = std::operator new[](n *
sizeof(T)) anzufordern, und dann per std::uninitialized_copy(orig, orig+n,
arr) das Originalarray orig hineinzukonstruieren.
|
Ein std::uninitialized_copy benutzt den Kopierkonstruktor, um die neuen
Elemente zu erzeugen. Du sparst also mit dieser Methode keinen
Konstruktoraufruf.
Um rohen Speicher anzufordern, würde ich malloc benutzen:
T * arr = static_cast<T *>(malloc(n * sizeof(*arr)));
| Quote: | Allerdings frage ich mich nun: Ist der einzig korrekte Weg, das ganze
rückgängig zu machen, über arr zu iterieren, auf jedem Objekt einen
Pseudodestruktoraufruf zu machen und den Speicher mit std::operator
delete[](arr) wieder freizugeben?
|
Ja, das ist der einzige weg, wobei ich hier dann free nehmen würde:
free(arr);
Christoph
--
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 |
|
 |
Mario Schunda Guest
|
Posted: Fri Mar 03, 2006 11:06 pm Post subject: Re: uninitialized_copy |
|
|
Hallo Markus
Meiner Meinung geht es so:
class cHuhu
{
public:
cHuhu(int J) { std::cout << "Konstructor " << J << std::endl; };
~cHuhu() { std::cout << "Destructor" << std::endl; };
};
template< class T >
T* CreateUninitialized(const T& Des)
{
T* pSrc = reinterpret_cast<T*>(new unsigned char [sizeof(T)]);
std::copy(&Des,
&Des + 1,
std::raw_storage_iterator<T*, T>(pSrc));
return pSrc;
};
int main(int argc, char **argv)
{
cHuhu Hu1(2);
cHuhu* pHu = CreateUninitialized(Hu1);
delete pHu;
........
Die letzte Zeile zeigt das Du delete Normal auf den Type anwendest da Du ja
eine fertig und Korrekt angelegt Klasse hast. So kannst Du auch den
Destruktor der Klasse benutzen.
Mario
--
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
|
Posted: Sat Mar 04, 2006 10:06 am Post subject: Re: uninitialized_copy |
|
|
Christoph Bartoschek wrote:
| Quote: | Markus Moll wrote:
Mal angenommen, ich habe eine Klasse (T), deren Objekte wirklich teuer
zu konstruieren sind, oder eine, die keinen Default-Konstruktor besitzt.
Jetzt möchte ich eine Kopie eines Arrays von T anlegen.
Ich dachte daran, rohen Speicher mit T* arr = std::operator new[](n *
sizeof(T)) anzufordern, und dann per std::uninitialized_copy(orig,
orig+n, arr) das Originalarray orig hineinzukonstruieren.
Ein std::uninitialized_copy benutzt den Kopierkonstruktor, um die neuen
Elemente zu erzeugen. Du sparst also mit dieser Methode keinen
Konstruktoraufruf.
|
Aber erst default-konstruieren und dann zuweisen ist aufwendiger.
| Quote: | Um rohen Speicher anzufordern, würde ich malloc benutzen:
T * arr = static_cast<T *>(malloc(n * sizeof(*arr)));
|
Warum? Ich würde operator new so verwenden, wie Markus das oben getan hat,
schon alleine, um mir den Cast zu ersparen.
--
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 |
|
 |
Markus Moll Guest
|
Posted: Sat Mar 04, 2006 2:06 pm Post subject: Re: uninitialized_copy |
|
|
Hallo
Rolf Magnus wrote:
| Quote: | Christoph Bartoschek wrote:
Um rohen Speicher anzufordern, würde ich malloc benutzen:
T * arr = static_cast<T *>(malloc(n * sizeof(*arr)));
Warum? Ich würde operator new so verwenden, wie Markus das oben getan hat,
schon alleine, um mir den Cast zu ersparen.
|
Das war allerdings mein Fehler. Operator new benötigt auch einen cast, den
habe ich einfach vergessen.
Ich bin leider gezwungen, ein dynamisches C-style array zu verwenden (geht
um Performance bei ausgeschalteten Optimierungen ). Insofern muß ich mir
quasi das "nötigste" des vector selbst schreiben, dazu gehört eben die
Konstruktion als Kopie eines anderen Arrays. Hab das jetzt auch soweit
korrigiert, daß nur noch operator new[], placement new, Destruktor und
operator delete[] (in dieser Reihenfolge) beteiligt sind.
Gibt es zwischen T und Array von T eigentlich möglicherweise
Alignment-Unterschiede? (Frage wegen operator new[] vs operator new)
Danke
Gruß
Markus
--
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 |
|
 |
Christoph Bartoschek Guest
|
Posted: Sat Mar 04, 2006 3:06 pm Post subject: Re: uninitialized_copy |
|
|
Rolf Magnus wrote:
| Quote: | Um rohen Speicher anzufordern, würde ich malloc benutzen:
T * arr = static_cast<T *>(malloc(n * sizeof(*arr)));
Warum? Ich würde operator new so verwenden, wie Markus das oben getan hat,
schon alleine, um mir den Cast zu ersparen.
|
Stimmt wohl, dass malloc nicht besser als operator new[] ist. Aber auch
operator new[] gibt nur void * zurück (und ist übrigends nicht im namespace
std), so dass der cast immer noch notwendig ist. Dadurch ist malloc doch
kürzer.
Zum Testen:
int main() {
int * arr = operator new[](10 * sizeof(*arr));
operator delete[](arr);
}
Ergibt hier:
mem.C: In function »int main()«:
mem.C:2: Fehler: ungültige Umwandlung von »void*« in »int*«
Christoph
--
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 |
|
 |
Jakob Bieling Guest
|
Posted: Sat Mar 18, 2006 9:27 pm Post subject: Re: uninitialized_copy |
|
|
Markus Moll <moll (AT) rbg (DOT) informatik.tu-darmstadt.de> wrote:
| Quote: | Mal angenommen, ich habe eine Klasse (T), deren Objekte _wirklich_
teuer zu konstruieren sind, oder eine, die keinen Default-Konstruktor
besitzt.
Jetzt möchte ich eine Kopie eines Arrays von T anlegen.
Ich dachte daran, rohen Speicher mit T* arr = std::operator new[](n *
sizeof(T)) anzufordern, und dann per std::uninitialized_copy(orig,
orig+n, arr) das Originalarray orig hineinzukonstruieren.
Allerdings frage ich mich nun: Ist der einzig korrekte Weg, das ganze
rückgängig zu machen, über arr zu iterieren, auf jedem Objekt einen
Pseudodestruktoraufruf zu machen und den Speicher mit std::operator
delete[](arr) wieder freizugeben?
|
Mit
template <typename T>
void destruct (T& t) { t.~T (); }
kannst du std::for_each benutzen. Ist dann im Endeffekt zwar das
gleiche wie ueber alle einzeln zu iterieren, nur eben schoen lesbar
verpackt:
std::for_each (arr, arr + n, destruct <T>);
hth
--
jb
(reply address in rot13, unscramble first)
--
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 |
|
 |
Jakob Bieling Guest
|
Posted: Sat Mar 18, 2006 9:41 pm Post subject: Re: uninitialized_copy |
|
|
Mario Schunda <weg_mario@familie-schunda.de> wrote:
| Quote: | Hallo Markus
Meiner Meinung geht es so:
class cHuhu
{
public:
cHuhu(int J) { std::cout << "Konstructor " << J << std::endl; };
~cHuhu() { std::cout << "Destructor" << std::endl; };
};
template< class T
T* CreateUninitialized(const T& Des)
{
T* pSrc = reinterpret_cast<T*>(new unsigned char [sizeof(T)]);
|
Halte ich fuer keine so gute Idee. Nach diesem reinterpret_cast ist
das ganze nicht mehr portable.
| Quote: | std::copy(&Des,
&Des + 1,
std::raw_storage_iterator<T*, T>(pSrc));
return pSrc;
};
int main(int argc, char **argv)
{
cHuhu Hu1(2);
cHuhu* pHu = CreateUninitialized(Hu1);
delete pHu;
|
Hier hast du dann wirklich undefined behaviour, da du jetzt delete
aber ein paar Zeilen weiter oben new[] benutzt. Mal abgesehn davon dass
char und cHuhu gaenzlich unverwandt sind und es deshalb selbst mit
delete[] nich besser waere.
Den Ansatz mit ::operator new und ::operator delete find ich da
wesentlich besser.
--
jb
(reply address in rot13, unscramble first)
--
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 |
|
 |
|
|
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
|
|