2017-02-15 3 views
0

Ich spiele herum und schreibe meine eigene Heap-Klasse. Für meine Template-Heap-Klasse müssen die Operatoren '> und' < 'für den Vorlagentyp definiert sein.C++ mit shared_ptr, aber die relationalen Operatoren meines Objekts aufgerufen?

Alles schien gut zu funktionieren, wenn eine Instanz einer Beispielklasse, die ich schrieb, verwendet wurde (und funktionierte auch gut auf int). Da es jedoch so viele Instanzen gibt, wie Klasseninstanzen von verschiedenen Knoten im Heap wechseln, entschied ich mich zu sehen, was passiert ist, als ich einen Heap von shared_ptr meiner Klasse erstellt habe. Während ich sah, dass die Anzahl der erstellten Instanzen weit nach unten ging, funktionierte der Heap nicht korrekt, da der Smart-Zeiger '>' und '<' aufgerufen wird, was ich denke, vergleicht nur intelligente Zeigerreferenzen. Eine Lösung, die mir in den Sinn kommt, ist die Berücksichtigung eines Vergleichstyps, genauso wie viele der STL-Typen, so dass ich meinen eigenen Vergleichstyp in die Heap-Klasse einbringen kann, die das shared_ptr dereferenziert und die Operation aufruft der zugrunde liegende Typ.

Einige Dokumente, die ich auf dem shared_ptr gelesen habe, sagten, dass sie den relationalen Operator (nämlich <) implementieren, so dass sie als Schlüssel in assoziativen Containern verwendet werden könnten. Ich versuche darüber nachzudenken, wann ich das shared_ptr als Schlüssel verwenden möchte, anstatt einen eigenen Schlüssel zu haben.

Haufen meiner Probe Art, die gut zu funktionieren scheint:

heap<foo> foo_heap(heap_type::max); 
for (unsigned int i = 0; i < 10; ++i) 
    { 
    std::string s = "string "; 
    s += ('0' + i); 
    foo f(i, s); 
    foo_heap.push(f); 
    } 
cout << "root: " << foo_heap.top() << endl; 

meine Probe-Klasse in einer Shared_ptr Einwickeln, die zB nicht funktioniert. Heap Constraint nicht in Bezug auf das, was ich zu erreichen versuche erfüllt.

heap<shared_ptr<foo>> foo_heap_smart(heap_type::max); 
for (unsigned int i = 0; i < 10; ++i) 
    { 
    std::string s = "string "; 
    s += ('0' + i); 
    shared_ptr<foo> f(new foo(i, s)); 
    foo_heap_smart.push(f); 
    } 
cout << "root: " << *(foo_heap_smart.top()) << endl; 

meine Probe foo Klasse:

class foo 
{ 
public: 
    foo(int value, std::string s) : _value(value), _s(s) 
    { 
     std::cout << "foo::foo()" << std::endl; 
    } 

    foo(const foo& f) : _value(f._value), _s(f._s) 
    { 
     std::cout << "foo::foo(const foo& f)" << std::endl; 
    } 

    ~foo() 
    { 
     std::cout << "foo::~foo()" << std::endl; 
    } 

    virtual void operator=(const foo& f) 
    { 
     std::cout << "foo::operator=()" << std::endl; 
     this->_value = f._value; 
     this->_s = f._s; 
    } 

    virtual bool operator<(const foo& right) 
    { 
     return this->_value < right._value; 
    } 

    virtual bool operator>(const foo& right) 
    { 
     return this->_value > right._value; 
    } 

    void print(ostream& stm) const 
    { 
     stm << "value: " << this->_value << ", s: " << this->_s; 
    } 

private: 
    int _value; 
    std::string _s; 
}; 

Also gehe ich davon aus, dass viele in ein ähnliches Problem ausgeführt haben. Ich frage mich nur, was die vorgeschriebene Lösung ist. Wie ich bereits erwähnt habe, denke ich, dass ich weiß, was erscheint, könnte eine gute Lösung sein, wollte aber überprüfen, wie es scheint, dass der intelligente Zeiger wegen ihrer Implementierung der relationalen Operatoren viele Probleme verursachen könnte.

Danke, Nick

+1

Die vorgeschriebene Lösung besteht darin, eine eigene Version des Vergleichsoperators bereitzustellen, wenn die Standardversion nicht Ihren Anforderungen entspricht. Ein besseres Design für Ihre "Heap" -Klasse wäre auch ein Comparator-Typ, der standardmäßig auf "std :: less" gesetzt werden kann. – Arunmu

+2

Wenn Sie sich Sorgen machen, dass zu viele Kopien erstellt werden, sollten Sie mehr über move semantics lernen springt direkt zu 'std :: shared_ptr'. –

+0

@miles, würde ich gerne über Umzug Semantik lernen. Kannst du mich auf einige Dokumente hinweisen?Ich habe mich gefragt, ob es einen speziellen Swap gibt, den ich verwenden könnte, der den Konstruktor/Destruktor umgehen würde. – nickdu

Antwort

1

Die vorgeschriebene Lösung ist Ihre eigene Version des Vergleichsoperators zur Verfügung zu stellen, wenn der Standard eines nicht Ihren Bedarf paßt. Ein besseres Design für Ihre heap Klasse wäre ein Comparator Typ, der standardmäßig std::less sein kann.

template <typename T, typename Comp = std::less<T>> 
class heap { 
... 
}; 

Und jetzt bieten Ihnen Version von less für shared_ptr spezialisiert besitzen.

template <typename T> 
struct less<shared_ptr<T>> { 
    bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const { 
     *a < *b; 
    } 
}; 

Für ein besseres Design, Sie cann einige metaprogramming Hack hinzufügen, um es nur T für Typ funktioniert, die verglichen werden können.

+0

danke. Meine Heap-Implementierung verwendet sowohl '>' als auch '<', so dass nur die Bereitstellung von weniger wahrscheinlich nicht ausreicht. Übrigens hatte ich geplant, Unterstützung für einen Vergleichstyp zuzulassen, wie es die STL-Klassen tun. – nickdu

+0

Ich möchte nur sicherstellen, dass ich verstehe, was genau du sagst. Sie erwähnen sowohl den Vergleichsoperator als auch den Vergleichstyp. Ist der Operator nur der Operator() auf der Vergleichsart? Da ich beide '<' and '>' verwende, frage ich mich, ob es besser wäre, einen Vergleichsoperator im Gegensatz zu einem Prädikat zu verwenden, so dass ich nur einen einzelnen optionalen Vergleichstyp anstelle von zweien benötigen kann. – nickdu

+0

@nickdu Verwenden von 'Operator <' oder ein Komparator wie oben ist im Grunde eine Wahl. Ich bevorzuge einen Comparator, da dieser als Typ in Template-Parametern übergeben werden kann und dies ist auch die Standard-Bibliothek. – Arunmu

Verwandte Themen