reinterpret_cast<const std::vector<const Bar*>& >(std::vector<Bar*>)



  • Hallo zusammen,

    ist dieser reinterpret_cast im folgenden Code immer ohne Probleme
    möglich?

    #include <vector>
    
    class Bar{
    };
    
    class Foo{
    public:
            std::vector<Bar*>& list(){
                    return vector;
            }
    
            const std::vector<const Bar*>& list() const {
                    return reinterpret_cast<const std::vector<const Bar*>& >(vector);
            }
    
            std::vector<Bar*> vector;
    };
    
    int main(int argc, char** arg) {
            Foo foo;
            Foo& foo1(foo);
            const Foo& foo2(foo);
            std::vector<Bar*>& vec1(foo1.list());
            const std::vector<const Bar*>& vec2(foo2.list());
            return 0;
    }
    

    Also intuitiv würde ich ja sagen, aber 100%ig sicher bin ich mir leider nicht.

    Gruß,
    XSpille

    EDIT: Ich verallgemeinere die Frage mal: Ist ein reinterpret_cast
    ohne Probleme möglich, wenn man eines (oder mehrere) der Template-Parameter
    in const umwandelt?



  • EDIT: Ich verallgemeinere die Frage mal: Ist ein reinterpret_cast
    ohne Probleme möglich, wenn man eines (oder mehrere) der Template-Parameter
    in const umwandelt?

    Nein. vector<const T*> und vector<T*> sind zwei verschiedene Typen. Nach Klausel 3.10 Paragraph 15 rufst Du damit undefiniertes Verhalten hervor.



  • Somit kommt jetzt die obligatorische Frage, was Du eigentlich machen möchtest. Wenn Du diese beantwortet hast, wirst Du mit eine Sammelsurium an schlauen Antworten, Lösungsansätzen und so mancher fast schon unglaubwürdig genialer Eingebung konfrontiert.

    Wenn Du Dich dem wirklich gewachsen fühlst, beschreibe Deinen Kontext. 🙂



  • krümelkacker schrieb:

    Nein. vector<const T*> und vector<T*>. Nach Klausel 3.10 Paragraph 15 rufst Du damit undefiniertes Verhalten hervor.

    thx 🙂

    Eisflamme schrieb:

    Somit kommt jetzt die obligatorische Frage, was Du eigentlich machen möchtest.

    Ich möchte gar nichts Konkretes machen. Die Frage schwirrte mir nur im Kopf rum.
    Ich denke manchmal könnte es praktisch sein, dass man nicht nur die
    Liste als const zurückliefert, sondern auch die darin enthaltenen Elemente. 🙂

    Wenn ich z. B. const Zugriff auf einen Pool habe und mir alle Elemente
    in dem Pool zurückgeben lasse, dann sollte niemand die Objekte darin verändern.



  • Hier wegen der Vollständigkeit noch der zugehörige Text:

    Klausel 3.10, Paragraph 15 schrieb:

    If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:

    • the dynamic type of the object,
    • a cv-qualified version of the dynamic type of the object,
    • a type that is the signed or unsigned type corresponding to the dynamic type of the object,
    • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of
      the object,
    • an aggregate or union type that includes one of the aforementioned types among its members (includ-
      ing, recursively, a member of a subaggregate or contained union),
    • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
    • a char or unsigned char type.


  • Da fast alles was du mit Vektoren tun willst mit Iteratoren funktioniert kannst du dir (z.B. mit Boost.Iterator) einen Filter-Iterator schreiben, der auf jedes Element einen

    const_cast
    

    anwendet (aber außer einem Vektor von Zeigern auf Stringliterale die du an alte C-Bibliotheken weitergeben willst fällt mir da jetzt nichts sinnvolles ein).



  • Es gibt noch boost::indirect_iterator. Das könnte auch praktisch sein.

    class Foo
    {
    public:
      ...
      typedef boost::indirect_iterator<
                 std::vector<Bar*>::iterator,
                 Bar
              > iterator;
      typedef boost::indirect_iterator<
                 std::vector<Bar*>::const_iterator,
                 const Bar
              > const_iterator;
    
      iterator begin() {return iterator(vect_.begin());}
      iterator end()   {return iterator(vect_.end());}
      const_iterator begin() const {return const_iterator(vect_.begin());}
      const_iterator end()   const {return const_iterator(vect_.end());}
      ...
    private:
      std::vector<Bar*> vect_;
      ...
    


  • @.filmor & krümelkacker: THX



  • Bei indirect_iterator -- so, wie ich den hier verwendet habe -- gibt's allerdings eine const-Lücke. Du kannst Dir vom const_iterator per .base() den gekapselten std::vector<Bar*>::const_iterator holen und darüber die Bar-Objekte verändern.



  • krümelkacker schrieb:

    Bei indirect_iterator -- so, wie ich den hier verwendet habe -- gibt's allerdings eine const-Lücke. Du kannst Dir vom const_iterator per .base() den gekapselten std::vector<Bar*>::const_iterator holen und darüber die Bar-Objekte verändern.

    Naja man kann auch const_cast nehmen. Wenn man mutwillig das const weghaben will, geht immer was, es geht ja vor allem darum, versehentliche änderungen auszuschließen. Wer benutzt versehentlich base() ?



  • > Wer benutzt versehentlich base() ?

    Ich wollt's nur erwähnt haben.


Log in to reply