in set mit smart-Pointer nach Zeiger suchen



  • hab ein set:

    std::set< boost::shared_ptr< SomeClass > > ints;

    Und hab nen Zeiger auf eine Instanz von SomeClass, die in dem set drin ist. Leider aber nur nen Zeiger, nicht keinen shared_ptr.

    Wie kann ich das finden (ohne linear zu suchen)?



  • Wie kann ich das finden (ohne linear zu suchen)?

    Ich würde mal sagen über die set gar nicht. Denn selbst wenn du den Raw-Pointer temporär in einen shared_ptr umwandeln könntest, würdest du den Wert nicht finden, denn: "two shared_ptr instances are equivalent if and only if they share ownership"

    Ich sehe folgende Möglichkeiten:
    1. du verwendest std::equal_range mit einem passenden cmp-Objekt:

    struct Cmp
    {
    public:
        bool operator()(const boost::shared_ptr<SomeClass>& lhs, SomeClass* rhs) const
        {
            return lhs.get() == rhs;
        }
        bool operator()(SomeClass* lhs, const boost::shared_ptr<SomeClass>& rhs) const
        {
            return lhs == rhs.get();
        }
    };
    
    typedef std::set< boost::shared_ptr< SomeClass > > Set;
    void func(SomeClass* p, Set& s)
    {
        std::pair<Set::iterator, Set::iterator> res = std::equal_range(s.begin(), s.end(), p, Cmp());
        if (res.first != res.second)
             // gefunden
    }
    

    Das ist zumindest in der Anzahl der Vergleiche logarithmisch. Da sets Iteratoren aber keine Random-Access-Iteratoren sind ist die Anzahl der nötigen Schritte natürlich linear in end()-begin().

    2. Du änderst die set in eine map.

    3. Du änderst dein Design so, dass du niemals gleichzeitig die selbe Ressource sowohl über einen Shared-Ptr als auch über einen Raw-Pointer referenzierst. Das ist generell eine gute Idee, da die Mischung von Raw- und Shared-Ptr irgendwie immer zu Problemen führt.
    Kannst du z.B. nicht statt der Raw-Pointer Iteratoren verwenden?

    Drittens ist natürlich am Schönsten, aber sicher nicht in allen Situationen möglich.



  • doppelposting



  • Mein Fall ist eigentlich ein Anwendungsfall für boost::weak_ptr. Das Objekt aus dem Container zu holen, wär eh schon ne schmutzige Lösung (wär aber schnell zu implementieren gewesen. Bin nämlich ziehmlich unter Druck, wegen des Problems: Hab ein Speicherleck wegen zwei Smart-Pointer-Objekten, die sich gegenseitig referenzieren.

    Blos hab ich leider in meinem realen Fall keine boost sondern einen selber geschriebenen referenzzählenden Smart-Pointer. Den verwend ich zwar eigentlich nicht mehr, aber der Code ist ein bisschen älter. Umstellen wäre auch ein ziehmlicher Aufwand.

    Hab inzwischen Angefangen, mir selber ne weak_ptr-Pendant zu schreiben. Is ja eigentlich garnet so schwierig:

    Könnt mal angucken, ob ich was wichtiges vergessen hab

    namespace tz
    {
       template <class T>
      class CXtAutoP
      {
        friend class CXtAutoPRef<T>;
    
        //...
    
        //privater Ctor
        CXtAutoP( T*        Pointer,
                  unsigned* puInstanzenZaehler)
        :m_Pointer( Pointer),
         m_puInstanzenZaehler( puInstanzenZaehler)
        { 
          ++*puInstanzenZaehler;  //Übernimmt Besitz -> hochzählen!
        };
        //...
      };
    }
    
    namespace tz
    {
      /// Nicht-Besitzende Referenz auf ein mit einem CXtAutoP gemanagetes Objekt
      /// (erfüllt dieselbe Aufgabe wie boost::weak_ptr)
       template <typename T>
       class
      CXtAutoPRef
      {
        ///Zeiger auf Objekt
        T* m_Pointer;
    
        //Zeiger auf Zähler
        unsigned* m_puInstanzenZaehler;
    
      public:
        CXtAutoPRef( const etz::CXtAutoP< T>& xap)
        :m_Pointer( xap.m_Pointer),
         m_puInstanzenZaehler( xap.m_puInstanzenZaehler)
        {
        }
    
         const etz::CXtAutoP< T>
        GetXap()
        {
          return etz::CXtAutoP<T>( m_Pointer,
                                   m_puInstanzenZaehler);
        }
      };
    }
    

Anmelden zum Antworten