2010-11-24 8 views
2

Ich verwende derzeit C++ 0x shared_ptr. Ich habe eine Dienstprogrammfunktion, die einen Zeiger auf ein Objekt aufnehmen muss, und die Dienstprogrammfunktion führt nur eine Leseoperation von dem Objekt aus, und ich könnte sicher sein, dass das Objekt immer noch existiert, wenn es den Zeiger dereferenzieren muss. Ich frage mich, was ist die beste Vorgehensweise, um den intelligenten Zeiger auf eine solche Funktion zu übertragen? Sollte ich den Smart Pointer per Referenz übergeben, nach Wert, oder könnte ich den rohen Pointer bekommen und ihn an die Funktion übergeben? Welche Methoden bieten die beste Leistung?Übergabe von Smart-Pointer um C++

Danke.

+0

Die einzige Möglichkeit zur Bestimmung der Leistung ist das Messen. Raten oder versuchen, es zu berechnen, ist normalerweise falsch, da der Compiler so viele Optimierungen durchführt, dass ein großer Teil des Codes tatsächlich entfernt wird. Schreiben Sie den Code das Maß und optimieren Sie es entsprechend. –

Antwort

3
  • Pass von Wert funktioniert OK für mich
  • Pass von Referenz könnte von jemand anderem empfohlen werden, aber ich glaube nicht, es lohnt sich
  • den Rohzeiger bekommen und weitergeben getan werden muss nur mit dem alten Code zu interagieren
  • Der springende Punkt von SP ist, dass Ihr Objekt nur dann stirbt, wenn keine Referenzen darauf existieren, also wenn Sie einen SP zur Hand haben, bedeutet dies, dass der Zeiger noch lebt (wenn geteilte Zeiger sind) richtig verwendet)
+0

Ich würde dieser Antwort noch eine weitere Aufzählung geben, um das anonyme Drive-by-Downvote abzubrechen, aber ich kann nur einmal abstimmen. :-( –

+1

@Downvoter: Könnten Sie bitte einen Kommentar hinterlassen? @Alf: Es ist OK, ich bin schon daran gewöhnt ... Ich denke, das ist die Art, wie die Menschheit funktioniert ... nicht nur SO Problem –

+8

Ich stimme überhaupt nicht zu Punkt 3. Das Übergeben von unformatierten Zeigern ist am flexibelsten, da Sie keine Anforderungen an den Aufrufer stellen, welche Art von Objektbesitz er verwendet.Das Übergeben einer Referenz ist möglicherweise besser, wenn das Objekt vorhanden sein muss, aber das Übergeben eines unformatierten Zeigers ist nicht nur für Legacy-Code. –

0

Die Antwort hängt vom intelligenten Zeigertyp ab. Gemeinsamer Zeiger können Sie als Wert übergeben, wie folgt aus:

class A 
{ 
    // implementation 
}; 

void foo(std::shared_ptr<A> p) 
{ 
    // use p 
} 

aber zum Beispiel std :: auto_ptr, können Sie nicht den oben tun, als das Objekt zerstört wird:

void boo (std::auto_ptr<A> p) 
{ 
// use p 
} // ops the resource pointer by p gets destructed 

Im zweiten Fall sollten Sie durch einen Verweis:

void boo (A &p) 
{ 
// use p 
} 
+0

std :: auto_ptr ist veraltet in C++ 0x –

+0

@Armen C++ 0x ist immer noch Entwurfsversion.Was ich sagen wollte ist, müssen Sie vorsichtig sein mit intelligenten Zeigern. –

+0

@Armen aber danke für Infos Das ist neu für mich. –

3

Wenn Sie nur den Zeiger dereferenzieren im Körper der Funktion und muß nicht den Zeiger für eine spätere Verwendung speichern (die auf irgendeine Art von gemeinsamer Trägerschaft impliziten nehmen würden), dann ist es am flexibelsten, die Funktion dazu zu bringen, einen rohen Zeiger (oder nur eine Referenz, wenn keine Notwendigkeit besteht, mit null/no-Objekt umzugehen) zu verwenden, da sie die Verwendung von Code erlaubt, der irgendeine Art von Besitz-Semantik verwendet, z. ein Zeiger auf eine lokale oder statische Variable, ein Mitglied eines Arrays oder einer anderen Struktur oder ein intelligenter Zeiger irgendeiner Art. Es ist eine fast universelle Konvention, dass, wenn Sie einen Zeiger auf etwas in einer Funktion übergeben, der Aufrufer dieses Objekt am Leben hält, bis die Funktion beendet wird. In der Tat müssten Sie in einer Multithread-Umgebung sein, um dies zu brechen.

Nur wenn Sie den Zeiger für die spätere Verwendung speichern müssen, muss die Funktion mit dem Anrufer bezüglich des Besitzes zusammenarbeiten. In diesem Fall müssen Sie die shared_ptr übergeben, die Sie nach Wert oder durch const Referenz tun können, ist es nicht sehr wichtig, welche als shared_ptr sind billig zu kopieren. Wenn Sie sehr auf die Leistung bedacht sind, können Sie profilieren, welche besser ist.

+1

+1: Intelligente Zeiger sind für Speicherverwaltung, eine Funktion, die nicht benötigt wird, ist am besten, einen Zeiger oder eine ** Referenz ** zu nehmen (wenn null kein gültiger Parameter ist). –

1

Ich werde für die dritte Option gehen. Wenn Sie eine Funktion entwerfen, die ein Objekt für einige Zeit verwendet, mit der Garantie, dass das Objekt für die gesamte Dauer des Gesprächs am Leben sein wird, dann sollte die Funktion Signatur nicht einen Zeiger überhaupt:

void foo(type & t); 
int main() { 
    std::shared_ptr<type> sp(new type); 
    foo(*sp); 
} 

Es gibt keinen Grund, foo zu begrenzen, um shared_ptr zu verwenden, wie oben beschrieben, können Sie Referenzen in Objekte übergeben, die nicht einmal dynamisch zugewiesen sind. Indem überhaupt kein Zeiger (nicht einmal ein roher Zeiger) übergeben wird, wird klargestellt, dass keine Eigentümersemantik mit der Funktion assoziiert ist (d. H.es wird keinen Zeiger für die spätere Verwendung behalten, es wird das Objekt nicht löschen) und es gibt an, dass das Objekt für die gesamte Dauer des Anrufs aktiv sein sollte.

3

Sie müssen nur einen Smart-Zeiger an eine Funktion übergeben, wenn Sie auch den Besitz des Zeigers angeben möchten.

Ich habe vor kurzem einen Artikel über Besitz Semantik bei der Weitergabe von std :: unique_ptr zu/von Funktionen geschrieben. Werfen Sie einen Blick http://timoch.com/blog/2013/04/std-unique_ptr-semantic/

Gegeben Struktur A:

struct A { int field; }; 

Passing ein Rohzeiger

// you make no statement of ownership 
// the caller stays the owner of the pointed object 
void useA(A* ptr) { 
    // useA simply uses the pointed object 
    // it should not delete it (because it does not own it) 
    ptr->field = 2; 
}  

von Wert Passing

std::vector<std::unique_ptr<A>> container; 

// the caller explicitly gives you ownership of the object 
void ownA(std::unique_ptr<A> ptr) { 
    // you can use the pointed object 
    std::cout << ptr->field << std::endl; 

    // the object pointed to by ptr is yours 
    // you can place it in a container that you own 
    container.push_back(std::move(ptr)); 
    // now container owns the pointed A instance 

    // if you do not move it using std::move() 
    // the pointed object is deleted automatically 
} 

Passing durch nicht konstante Referenz

// the caller is giving you the opportunity to take ownership of the object 
// it is free to not take it though 
void maybeOwnA(std::unique_ptr<A> & ptr) { 
    // ptr is passed by reference 
    // so maybeOwnA can decide based on its own internal 
    // to take ownership of the pointed object 

    // taking ownership requires that std::move is called on ptr 

    // it may also simply use the pointed object and not 
    // take ownership 
} 

void callMaybeOwnA() { 
    std::unique_ptr<A> ptr = new A(); 
    maybeOwnA(ptr); 
    // we know if we still own the instance of A 
    // by looking at ptr 
    if (ptr.get() != nullptr) { 
     // we still own the pointed object 
    } 
} 

Vorbei const-Referenz

// this is functionally the same as passing a raw pointer 
// but you force the caller to use a std::unique_ptr to call you 
// the caller will not be able to use a std::shared_ptr for example 
// I strongly recommend against this form. Passing a raw pointer is 
// perfectly fine 
void useA(const std::unique_ptr<A> & ptr) { 
    // ptr is const so you cannot call std::move on it 
    // you effectively cannot own it 
} 

// a factory function should return a std::unique_ptr by value 
// the caller owns the pointed object 
std::unique_ptr<A> factory() { 
    return std::unique_ptr<A>(new A()); 
} 

void callFactory() { 
    std::unique_ptr<A> ptr = factory(); 
    // the pointed object is deleted when ptr goes out of scope 
} 

Das gleiche gilt für std :: shared_ptr gilt. Wenn die Funktion einfach den Zeiger verwendet und zurückgibt, gibt es keinen Grund, ein std :: shared_ptr zu übergeben. Sie müssen nur ein std :: shared_ptr übergeben, wenn Sie dem Objekt, an das Sie sich wenden, den gemeinsamen Eigentümer des spitzen Objekts geben möchten. Zum Beispiel, wenn die Funktion den Zeiger speichert und erwartet, dass er nach der Rückkehr verwendet werden kann (wenn er zum Beispiel erneut aufgerufen wird).

Ich hoffe, es hilft.

TiMoch

0

Die Antwort ist sehr einfach - tun, was Sie mit relativ billigen Kopie Kosten mit jeder anderen Klasse zu tun.

Hinweis Das Kopieren von Smartpointern ist nicht so günstig wie das Kopieren von ganzen Zahlen. Es liegt wahrscheinlich zwischen Ganzzahlen und kleinen std :: string. (Ich arbeitete in einem Projekt mit allen Smartpointern, die per Wert gesendet wurden, und das Inkrementieren und Dekrementieren der Referenzzählung von Smartpointern dauerte zwischen 4-6% der Zeit).

Wenn Sie beispielsweise std :: string als Referenz übergeben möchten, sollten Sie dies wahrscheinlich auch für Smart Pointer tun.

Wenn Sie Referenz verwenden (was ich persönlich empfehle) const-Verweis verwenden - auf diese Weise ermöglichen Sie dem Compiler implizite Upcast der referenzierten Klasse, wo es benötigt wird.

Verwandte Themen