2008-11-03 8 views
17

Ich möchte in einem Vektor von Object-Zeigern für ein passendes Objekt finden. Hier ist ein Beispielcode, um mein Problem zu veranschaulichen:Wie finde ich Algorithmus mit einem Zeigervektor auf Objekte in C++?

class A { 
public: 
    A(string a):_a(a) {} 
    bool operator==(const A& p) { 
     return p._a == _a; 
    } 

private: 
    string _a; 
}; 

vector<A*> va; 

va.push_back(new A("one")); 
va.push_back(new A("two")); 
va.push_back(new A("three")); 

find(va.begin(), va.end(), new A("two")); 

Ich möchte das zweite Element in den Vektor geschoben finden. Da Vektor jedoch als eine Pointers-Auflistung definiert ist, verwendet C++ meinen überladenen Operator nicht, sondern verwendet einen impliziten Zeigervergleich. Was ist der bevorzugte C++ - Lösungsansatz in dieser Situation?

Antwort

17

Verwenden find_if mit einem Funktor:

template <typename T> 
struct pointer_values_equal 
{ 
    const T* to_find; 

    bool operator()(const T* other) const 
    { 
     return *to_find == *other; 
    } 
}; 


// usage: 
void test(const vector<A*>& va) 
{ 
    A* to_find = new A("two"); 
    pointer_values_equal<A> eq = { to_find }; 
    find_if(va.begin(), va.end(), eq); 
    // don't forget to delete A! 
} 

Hinweis: Ihr Operator == für A sein sollte const, oder, noch besser, schreiben Sie es als Nicht-Mitglied friend-Funktion.

+0

Ich denke, es muss find_if im Code sein? – esrkan

+0

In der Tat - Sie können nur std :: find() ein Prädikat in einem Container von Prädikaten! – MSalters

+0

James können Sie weitere Erklärung ab dieser Zeile hinzufügen pointer_values_equal eq = {to_find}; – yesraaj

4

Verwenden Sie entweder std :: find_if und geben Sie ein geeignetes Prädikat selbst an. Weitere Beispiele finden Sie in den anderen Antworten.

Oder als Alternative einen Blick auf boost::ptr_vector, die den Zugriff auf Elemente transparent Referenz zur Verfügung, die als Zeiger wirklich gespeichert werden (als Extra-Bonus wird Speicherverwaltung für Sie als auch behandelt)

1

Sie auch nutzen könnten boost :: Lambda:

using namespace boost::lambda; 
find_if(va.begin(), va.end(), *_1 == A("two")); 

natürlich sollten Sie es vorziehen shared_ptrs verwenden, damit Sie sich nicht erinnern müssen löschen!