std::any Speicheradresse des unterliegenden Objekts



  • Hallo,

    Das kann man scheinbar nicht machen, ohne den Typ des unterliegenden Objekts zu kennen. D.h. std::any_cast<void>(&any) gibt mir nullptr weil die type_info nicht übereinstimmt. std::any_cast<void*>(any) gibt mir bad_any_cast.

    Ich finde das fehlt irgendwie, ein Member, das dir void* zurückgibt oder so. Das müsste von der Implementierung her doch irgendwie machbar gewesen sein oder nicht? Warum kann man das nicht machen?



  • Was willst du mit einer Adresse von den Interna einer Klasse?

    btw. "unterliegendes Objekt" ... das heißt contained value.

    @spiri sagte in std::any Speicheradresse des unterliegenden Objekts:

    Warum kann man das nicht machen?

    Weil es dafür keinen (sinnvollen) Anwendungsfall gibt.



  • Weil ich eine Liste davon habe. Und löschen tu ich die Einträge anhand der Adresse des unterliegenden Objekts. Und der Typ des unterliegenden Objekts ist nicht bekannt, kann also kein std::addressof(std::any_cast<T&>(any)) machen.

    EDIT: Daher hätte es mich irgendwie gefreut, wenn das Ding ein void* any::address() Member hätte o.ä.

    Gelöst hab ich das Problem eben mit unordered_map<void*, std::any>. Dabei speichere gleich die Adresse des unterliegenden Objekts als Key, dann kann ich das Objekt wiederfinden.



  • @spiri sagte in std::any Speicheradresse des unterliegenden Objekts:

    Weil ich eine Liste davon habe. Und löschen tu ich die Einträge anhand der Adresse des unterliegenden Objekts.

    Nochmal: Es gibt kein "unterliegendes Objekt". Warum tuts nicht die Adresse des anys?



  • @Swordfish sagte in std::any Speicheradresse des unterliegenden Objekts:

    Warum tuts nicht die Adresse des anys?

    Meine Liste ist privater Bestandteil einer Klasse. any soll also nur ein Implementierungsdetail sein, davon soll man bei der späteren Anwendung der Klasse nichts mitbekommen. Von außenhin kennt man nur die Referenz auf das tatsächliche Objekt. Und von außenhin will ich die Elemente aus der Liste wieder entfernen können.



  • Wenn der Anwender die Adresse des Dings kennt, das er hineingesteckt hat, dann kennt er auch den Typ.



  • Das passt nicht wirklich zusammen... std::any ist ein value Objekt. Das kann man rumkopieren, dann kann sich die Adresse des contained values ändern oder auch nicht. Das irgendwie zu kombinieren schaut für mich erstmal nach einem nicht durchdachten Hack aus. Mag so funktionieren, wie du das gemacht hast, später wird das System aber größer, man kopiert die Objekte doch rum usw., und dann funktioniert das nicht mehr.



  • @Swordfish sagte in std::any Speicheradresse des unterliegenden Objekts:

    Wenn der Anwender die Adresse des Dings kennt, das er hineingesteckt hat, dann kennt er auch den Typ.

    Ja das stimmt aber in meinem Fall leider nicht.

    Ich schreibe mir eigene cURL-Klassen fürs HTTP, die intern ein Aggregat zu einem Buffer (Typ T) halten. Meine Request-Klassen sind also Templates. Einziges Problem dabei ist, dass ich Klasseninstanizerungen der selben Klasse aber verschiedenen Template-Params nicht in einer einzigen Liste abspeichern kann. Das will ich aber machen können, wenn ich späterhin auch ein Connection Pool einbauen will (eine http_manager-Klasse).

    Ist übrigens auf Github.

    Was ich dann gemacht habe ist ein abstraktes Interface curl_base ohne Template-Param. Das Interface definiert also alle pure Virtuals, die ich in den späteren abgeleiteten Klassen (http_request<>) benutzen kann. Darunter fällt nunmal auch virtual void* curl_base::buffer_ptr() const = 0. Ich muss mindestens die Adresse des unterliegenden Buffers kennen. Das geht nicht anders, weil abspeichern tu ich die Objekte in meinem http_manager mit std::list<std::unique_ptr<curl_base>>. Und außer der rohen void-Adresse des unterliegenden Buffers kann ich über curl_base keine Information bereitstellen.

    Wenn ich nun händisch ein Objekt aus dem http_manager löschen will, mache ich das mit dieser Methode:

        class http_manager : public async_handle{
            std::list<std::unique_ptr<curl_base>> handles;
            std::unordered_map<void*, std::any> buffers;
    ...
    public:
            http_manager& remove(curl_base& task) override{
                async_handle::remove(task);
    
                buffers.erase(std::find_if(buffers.begin(), buffers.end(), [&task](const std::pair<void*, std::any>& buffer){
                    return task.buffer_ptr() == buffer.first;
                }));
    
                handles.erase(std::find_if(handles.begin(), handles.end(), [&task](const std::unique_ptr<curl_base>& handle){
                    return handle->native() == task.native();
                }));
    
                return *this;
            }
    ...
    };
    

    Also alles nur wegen ich kann nicht die selbe Klasse mit unterschiedlichen Template-Params in einer Liste abspeichern... 🙂

    @Mechanics sagte in std::any Speicheradresse des unterliegenden Objekts:

    Das kann man rumkopieren, dann kann sich die Adresse des contained values ändern oder auch nicht. Das irgendwie zu kombinieren schaut für mich erstmal nach einem nicht durchdachten Hack aus. Mag so funktionieren, wie du das gemacht hast, später wird das System aber größer, man kopiert die Objekte doch rum usw., und dann funktioniert das nicht mehr.

    Das funktioniert. Ich speichere die Objekte in einer Liste mit any um dessen Lebenszeit zu garantieren. Das ist alles. Die Liste soll das Ding nur am Leben halten. Irgendwann wird dann über die remove-Methode das Element aus der Liste gelöscht, aber ich muss das anhand von curl_base machen. Und dieser kennt nur curl_base::buffer_ptr().

    Mit einer unordered_map funktioniert es jedenfalls. Aber std::list kann ich hierfür nicht nehmen.



  • @Swordfish sagte in std::any Speicheradresse des unterliegenden Objekts:

    Weil es dafür keinen (sinnvollen) Anwendungsfall gibt.

    Darüber kann man sicherlich streiten. Boost::any hat jedenfalls genau diese geforderte Funktion.



  • @Jockelx sagte in std::any Speicheradresse des unterliegenden Objekts:

    Boost::any hat jedenfalls genau diese geforderte Funktion.

    Falls Du auf boost::unsafe_any_cast anspielst:

    // Note: The "unsafe" versions of any_cast are not part of the
    // public interface and may be removed at any time. They are
    // required where we know what type is stored in the any and can't
    // use typeid() comparison, e.g., when our types may travel across
    // different shared libraries.
    


  • @Swordfish
    Ja, darauf spiele ich an. Offenbar habe sie zumindest mal gedacht, dass das sinnvoll ist, so eine Funktion zu haben.
    Daher war mir deine Aussage (gibt keinen Anwendungsfall) zu absolut.



  • Hab damit aber jetzt gerade ein anderes Problem bekommen. ValueType von std::any muss copy-constructible sein. Sowohl im Std als auch bei Boost.

    D.h. meine Klasse funktioniert gerade nicht für IOStreams. Also muss ich mir jetzt eh selbst was zusammenbauen.



  • @Jockelx sagte in std::any Speicheradresse des unterliegenden Objekts:

    Ja, darauf spiele ich an. Offenbar habe sie zumindest mal gedacht, dass das sinnvoll ist, so eine Funktion zu haben.

    Es is IMHO ein Unterschied, so eine Funktion intern in einer library zu haben. Der Librarybauer hat die Kontrolle darüber, wie sich seine Klasse ändert.



  • @Swordfish

    Ja, stimmt. Ich dachte die wäre public und nur deprecated.



  • Hab herausgefunden, dass man auch einen unique_ptr<void, void(*)(void*)> verwenden kann, insofern man den Deleter selbst definiert. D.h. ich kann jetzt auch komplett auf std::any verzichten 🙂


Anmelden zum Antworten