Register for your free account! | Forgot your password?

Go Back   elitepvpers > Coders Den > C/C++
You last visited: Today at 11:05

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Warum std::make_unique anstatt new

Discussion on Warum std::make_unique anstatt new within the C/C++ forum part of the Coders Den category.

Reply
 
Old   #1
 
_Roman_'s Avatar
 
elite*gold: 0
Join Date: May 2010
Posts: 1,620
Received Thanks: 237
Warum std::make_unique anstatt new

Hallo,

ich habe heute gelesen, dass man
Code:
std::unique_ptr<Typ> up(std::make_unique<Typ>());
anstatt
Code:
std::unique_ptr<Typ> up(new Typ());
benutzen soll (weils exception-safe ist?) und ich verstehe nicht so ganz warum. Ich habe auch schon einige Sachen dazu gelesen, aber es funkt trotzdem nicht.

Genauso bei std::shared_ptr und std::make_shared

Wenn ich schon bei dem Thema bin. Warum kann ich einen shared pointer einer Funktion als Parameter übergeben aber keinen unique pointer?
_Roman_ is offline  
Old 09/18/2015, 20:36   #2
 
Padmak's Avatar
 
elite*gold: 58
Join Date: Jun 2008
Posts: 2,311
Received Thanks: 8,420
Quote:
Originally Posted by _Roman_ View Post
Wenn ich schon bei dem Thema bin. Warum kann ich einen shared pointer einer Funktion als Parameter übergeben aber keinen unique pointer?
Das ist einfach beantwortet, ein unique_ptr ist noncopyable, ein shared_ptr nicht

Deine andere Frage ist ein bisschen schwieriger zu beantworten, soweit ich weiß (bitte korrigiert mich jemand, wenn ich falsch liege) kann make_XXX den erzeugten Speicher wieder freigeben falls eine Exception im Konstruktor der Klasse auftritt, die Erzeugung mit new kann das natürlich nicht automatisch.

Außerdem finde ich persönlich schlicht klarer (da kürzer)
Vergleiche:
Code:
auto p = std::make_unique<Typ>(arg1);
vs
Code:
auto p = std::unique_ptr<Typ>(new Typ(arg1));
Du erwähnst, dass "es" trotzdem nicht funktioniert, was meinst du damit? Wenn make_unique nicht gefunden wurde, dann hast du eine Compilerversion die evtl ein bisschen zu alt ist, bzw hast c++14 nicht aktiviert
Im 11er Standard wurde die Funktion schlicht vergessen

Padmak
Padmak is offline  
Thanks
2 Users
Old 09/18/2015, 21:02   #3
 
_Roman_'s Avatar
 
elite*gold: 0
Join Date: May 2010
Posts: 1,620
Received Thanks: 237
Danke erstmal

Quote:
Das ist einfach beantwortet, ein unique_ptr ist noncopyable, ein shared_ptr nicht
Ok und durch den shared_ptr wird dann der kopierte shared_ptr am Ende mitgelöscht, richtig? Aber ich wusste gar nicht, dass pointer als Parameter kopiert werden, oder verstehe ich das falsch mit dem noncopyable?

Quote:
Deine andere Frage ist ein bisschen schwieriger zu beantworten, soweit ich weiß (bitte korrigiert mich jemand, wenn ich falsch liege) kann make_XXX den erzeugten Speicher wieder freigeben falls eine Exception im Konstruktor der Klasse auftritt, die Erzeugung mit new kann das natürlich nicht automatisch.

Außerdem finde ich persönlich schlicht klarer (da kürzer)
Vergleiche:
Code:
auto p = std::make_unique<Typ>(arg1);
vs
Code:
auto p = std::unique_ptr<Typ>(new Typ(arg1));
Du erwähnst, dass "es" trotzdem nicht funktioniert, was meinst du damit? Wenn make_unique nicht gefunden wurde, dann hast du eine Compilerversion die evtl ein bisschen zu alt ist, bzw hast c++14 nicht aktiviert
Im 11er Standard wurde die Funktion schlicht vergessen

Padmak
Ich nehme mal an, der erzeugte Speicher wird dann von den smart pointern im std::default_delete bzw. explizit angegeben destruktor freigegeben richtig? Oder haben smart pointer einfach so einen Mechanismus bezüglich der Exceptions?.

Mit funkt meinte ich einfach nur, dass es in meinem Kopf nicht gefunkt hat. Ich hab nämlich den größten Teil verstanden, als ich mir das Zeug zusammengelesen hab, aber da fehlte halt das letzte Puzzleteil
_Roman_ is offline  
Old 09/18/2015, 21:23   #4
 
elite*gold: 198
Join Date: Mar 2011
Posts: 835
Received Thanks: 263
Quote:
Originally Posted by _Roman_ View Post
Danke erstmal


Ok und durch den shared_ptr wird dann der kopierte shared_ptr am Ende mitgelöscht, richtig? Aber ich wusste gar nicht, dass pointer als Parameter kopiert werden, oder verstehe ich das falsch mit dem noncopyable?



Ich nehme mal an, der erzeugte Speicher wird dann von den smart pointern im std::default_delete bzw. explizit angegeben destruktor freigegeben richtig? Oder haben smart pointer einfach so einen Mechanismus bezüglich der Exceptions?.

Mit funkt meinte ich einfach nur, dass es in meinem Kopf nicht gefunkt hat. Ich hab nämlich den größten Teil verstanden, als ich mir das Zeug zusammengelesen hab, aber da fehlte halt das letzte Puzzleteil
Ein shared_ptr ist kein Pointer sondern ein Objekt welches sich wie einer verhält. -> Du kopierst nicht einen Pointer, du kopierst ein Objekt.

Kannst ja mal schauen, wie viel grösser ein shared_ptr<int> als ein int* ist.


Code:
auto bar = std::make_shared<int> (20);
int *foo;
std::cout << sizeof(bar) << std::endl;
std::cout << sizeof(foo) << std::endl;
ƬheGame is offline  
Thanks
1 User
Old 09/18/2015, 21:33   #5
 
elite*gold: 46
Join Date: Oct 2010
Posts: 782
Received Thanks: 525
Aber ein shared_ptr weiß nicht, von welchem shared_ptr er kopiert wurde (hatte der themenersteller ja angenommen), sondern mit dem Objekt (das, worauf der shared_ptr zeigt) wird ein weiters Objekt (meine ich, kann sein, dass es auch nur ein int ist) allokiert, welches speichert wie viele Referenzen (shared_ptr, deren Destruktor noch nicht aufgerufen wurden und die auf dieses Objekt zeigen) es gibt. Wenn die Zahl durch den Destruktor 0 werden würde, wird das Objekt gelöscht.
th0rex is offline  
Thanks
1 User
Old 09/28/2015, 17:43   #6
 
elite*gold: 225
Join Date: Sep 2014
Posts: 334
Received Thanks: 461
Quote:
Originally Posted by _Roman_ View Post
Wenn ich schon bei dem Thema bin. Warum kann ich einen shared pointer einer Funktion als Parameter übergeben aber keinen unique pointer?
eig. kann man das, nur nicht per copy argument, sondern als referenz.
~ correct me, wenn ich falsch bin, hab das mal gehört.
Cyrex' is offline  
Thanks
1 User
Old 09/28/2015, 20:09   #7
 
Padmak's Avatar
 
elite*gold: 58
Join Date: Jun 2008
Posts: 2,311
Received Thanks: 8,420
Quote:
Originally Posted by Padmak View Post
Das ist einfach beantwortet, ein unique_ptr ist noncopyable, ein shared_ptr nicht
Exakt.

Padmak
Padmak is offline  
Old 10/08/2015, 12:43   #8


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,394
Der Grund dafür, dass du einen unique_ptr nicht einfach so als Parameter übergeben kannst und einen shared_ptr schon, ergibt sich bereits aus dem Namen. Ein unique_ptr hat einen einzigen, eindeutigen Besitzer (er setzt das Konzept durch, dass jede Ressource einem eindeutigen Besitzer zugeordnet ist, der für sie verantwortlich ist). Einen unique_ptr zu übergeben, bedeuetet, dass das Objekt seinen Besitzer wechselt. Ein Besitzerwechsel bedeutet wiederum, dass der alte Pointer ungültig werden muss (es kann nur einen Besitzer geben). Daher musst du so einen Transfer explizit mit std::move veranlassen:

Code:
unique_ptr<int> p1 = make_unique<int>(42);
unique_ptr<int> p2 = std::move(p1); // p1 nun ungültig
Wenn du den Pointer nur kurz "ausleihen" (d.h. die Funktion verwendet ihn, speichert ihn aber nirgendwo, weshalb es im Prinzip zu einem gegebenen Zeitpunkt weiterhin nur einen Besitzer gibt) möchtest, kannst du das mit const Referenzen machen:

Code:
void func (const unique_ptr<int> &ptr)
{
    //hier kannst du das Objekt, auf das ptr zeigt, verwenden, aber es ihm nicht wegnehmen
    //kopien von ptr sind somit nicht gestattet
}

// geht nun, weil func nur eine Referenz erwartet und somit nichts kopiert wird
func(ptr);
Hier ist die Thematik und die möglichen Alternativen noch mal etwas ausführlicher dargestellt:

shared_ptr dagegen ist für einen geteilten Besitz gedacht. Es kann mehrere Besitzer für dieselbe Ressource geben, weshalb shared_ptr ein Kopieren erlaubt und du nicht auf expliziten Transfer oder Referenzen angewiesen bist. shared_ptr führt einen Referenzzähler, um festzuhalten, wie viele Besitzer es gibt. Erreicht der Zähler 0, wird das Objekt gelöscht.
Dieses Prinzip kommt einem Garbage Collector, wie man ihn aus C# oder Java kennt, sehr nahe, ist allerdings nicht exakt gleich. Ein shared_ptr gibt die Ressource nämlich sofort frei, wenn der Zähler 0 wird, während ein GC den Zeitpunkt der Freigabe etwas komplexer bestimmt. Außerdem kommt ein GC mit zirkulären Abhängigkeiten in der Objektstruktur klar, während du bei reiner Verwendung von shared_ptr damit ein Leak verursachen kannst (Objekt A hat einen Verweis auf B, weshalb der Zähler für B auf 1 bleibt, B hat einen Verweis auf A, weshalb dessen Zähler ebenfalls auf 1 bleibt => A und B werden nie gelöscht). Diese Kreise musst du mit Verwendung von weak_ptr explizit auflösen (du bestimmst also wieder einen eindeutigen Besitzer, der für die Löschung verantwortlich ist).

In der Regel ist unique_ptr zu bevorzugen, weil du dir ohnehin immer um das Konzept Besitz Gedanken machen musst. Ein shared_ptr nimmt dir diese Bürde wie gesagt nur teilweise ab. shared_ptr solltest du nur verwenden, wenn es einen wirklichen Bedarf dafür gibt, dass eine Ressource zwischen mehreren Besitzer über einen längeren Zeitraum geteilt wird.
MrSm!th is offline  
Thanks
1 User
Old 10/09/2015, 07:36   #9
 
_Roman_'s Avatar
 
elite*gold: 0
Join Date: May 2010
Posts: 1,620
Received Thanks: 237
Quote:
Originally Posted by MrSm!th View Post
Wenn du den Pointer nur kurz "ausleihen" (d.h. die Funktion verwendet ihn, speichert ihn aber nirgendwo, weshalb es im Prinzip zu einem gegebenen Zeitpunkt weiterhin nur einen Besitzer gibt) möchtest, kannst du das mit const Referenzen machen:

Code:
void func (const unique_ptr<int> &ptr)
{
    //hier kannst du das Objekt, auf das ptr zeigt, verwenden, aber es ihm nicht wegnehmen
    //kopien von ptr sind somit nicht gestattet
}

// geht nun, weil func nur eine Referenz erwartet und somit nichts kopiert wird
func(ptr);
Wenn ich das mit einer const Referenz mache, kann ich damit auch Dateien schließen? Also es geht um folgenden Code:

Code:
QString extractFromCSV(const std::unique_ptr<QFile> file)
{
	if (file->open(QFile::ReadOnly) && file->isReadable()) 
	{
		const QString temp = QString::fromLatin1(file->readAll());
		file->close();
		return temp;
	}

	return "";
}
Mit der const Referenz funktioniert das weiterhin, richtig? Das const ist ja top-level und bezieht sich auf den Pointer selber, wenn ich mich nicht irre.
Gilt file->close(); als schreibender Zugriff?
_Roman_ is offline  
Old 10/09/2015, 14:32   #10
 
Padmak's Avatar
 
elite*gold: 58
Join Date: Jun 2008
Posts: 2,311
Received Thanks: 8,420
Wenn du es compilen kannst, funktioniert es.
constness ist nicht direkt ein Runtime-Attribut, sondern wird vom Compiler überprüft und wenn nötig als Fehler reported.

Aber deine Argumentation ist richtig, du kannst den std::unique_ptr nicht verändern, den Inhalt dagegen aber schon, da du mit dem ->-Operator auf ein QFile zugreifst, nicht auf ein const QFile

Padmak
Padmak is offline  
Thanks
1 User
Old 10/09/2015, 16:35   #11


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,394
Quote:
Mit der const Referenz funktioniert das weiterhin, richtig? Das const ist ja top-level und bezieht sich auf den Pointer selber, wenn ich mich nicht irre.
Gilt file->close(); als schreibender Zugriff?
Richtig, const bezieht sich in dem Fall auf das Smartpointer-Objekt und nicht auf das Objekt, auf das der Smartpointer zeigt. Du kannst also non-const Methoden des Objekts aufrufen; bei den Methoden des Smartpointers musst du dich allerdings auf const Methoden beschränken, weshalb du z.B. release() in extractFromCSV nicht aufrufen (und somit die Ressource nicht an einen anderen Smartpointer transferieren) kannst - ist ja auch der Sinn des Ganzen.

Wenn die close() Methode keinen const Qualifier hat, dann gilt es als schreibender Zugriff, ja. Davon würde ich mal stark ausgehen, da das Schließen eines Handles bedeutet, den Objektzustand zu ändern (der open() Aufruf übrigens auch). Spielt hier aber wie gesagt keine Rolle, da es kein unique_ptr<const QFile> ist.

Quote:
constness ist nicht direkt ein Runtime-Attribut
Wenn man pedantisch sein will: Das ist nicht näher definiert. Der Compiler kann als const deklarierte Variablen, sofern ihr Wert schon zur Compilezeit feststeht, z.B. in einen read-only Bereich im Speicher platzieren oder direkt die Werte an den verwendeten Stellen einsetzen und ganz auf eine Variable verzichten. Es kann also durchaus auch Auswirkungen auf die Laufzeit haben.
MrSm!th is offline  
Thanks
1 User
Old 10/09/2015, 18:43   #12
 
Padmak's Avatar
 
elite*gold: 58
Join Date: Jun 2008
Posts: 2,311
Received Thanks: 8,420
Okay, aber das worauf du dich hier beziehst, ist eher constexpr als const, oder? (Zumindest der Teil, bei dem der Wert schon zur Compilezeit feststeht)

Ich meinte eher solche Sachen wie er hier im Thread braucht, würde man eine der Klassen im Speicher einfach verändern (Wieso sollte man, aber trotzdem), gäbe es keine Exception, sondern es würde einfach durchgehen

Padmak
Padmak is offline  
Thanks
1 User
Old 10/10/2015, 11:26   #13
 
elite*gold: 46
Join Date: Oct 2010
Posts: 782
Received Thanks: 525
Quote:
Originally Posted by Padmak View Post
Okay, aber das worauf du dich hier beziehst, ist eher constexpr als const, oder? (Zumindest der Teil, bei dem der Wert schon zur Compilezeit feststeht)
Afaik liegt der Unterschied darin, wann sie mit dem Wert initialisiert werden. Variablen, die mit const deklariert wurden, können auch zur Laufzeit ihren Wert bekommen. Mit constexpr deklarierte Werte müssen aber zur Compilezeit auch initialisiert werden. Aber ein Compiler darf mit const deklarierte Werte auch zur Compilezeit initialisieren und in einen read-only Bereich packen oder halt komplette eliminieren, wie Mr.Smith schon gesagt hat. Aber manche mit const deklarierte Werte können erst zur Laufzeit berechnet werden, wie z.B. konstante Referenzen oder Pointer, weswegen du schon recht damit hast, dass das sich eher auf constexpr bezieht.
th0rex is offline  
Thanks
2 Users
Reply


Similar Threads Similar Threads
Blaues Reich will nicht warum warum warum???
05/23/2011 - Metin2 Private Server - 6 Replies
hei leute, hab mir zuhause nen metin2 pvp installiert, für freunde. Alles ist schön und gut nur niemand kann sich ins blaue reich einloggen, bei gelb und rot haben wir keine probleme. Was könnte das problem sein :confused:, bitte um hilfe. thanx an alle.
Patcher fehler warum ka warum alles ausprobirt was mir einfil
01/14/2011 - Flyff Private Server - 9 Replies
in kilu .de meine Adresse ist da Index of / und dann so und ich habe alles nach sedrikas tut gemacht hier mein patch zum downloaden http://ffspatch.co.de/patch/FlyffDE/RESCLIENT/FFS .exe
warum SPOP warum GSG 9 warum SWAT,OMOH,SAS
05/30/2010 - CrossFire - 5 Replies
ich möchte hier von anderen hören (test bericht) warum ihr SPOP,GSG9,OMOH,SWAT,SAS spielt ich würde mir vieleicht die SPOP holen was sind ihr vorteile



All times are GMT +2. The time now is 11:05.


Powered by vBulletin®
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2024 elitepvpers All Rights Reserved.