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 mirnullptr
weil dietype_info
nicht übereinstimmt.std::any_cast<void*>(any)
gibt mirbad_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
any
s?
-
@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 (einehttp_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 auchvirtual 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 meinemhttp_manager
mitstd::list<std::unique_ptr<curl_base>>
. Und außer der rohen void-Adresse des unterliegenden Buffers kann ich übercurl_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 voncurl_base
machen. Und dieser kennt nurcurl_base::buffer_ptr()
.Mit einer
unordered_map
funktioniert es jedenfalls. Aberstd::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.
-
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 aufstd::any
verzichten