Fehler: kein geeigneter Standardkonstruktor verfügbar with
[Protocol=boost::asio::ip::tcp"]
Ich bin nicht mal sicher ob das move unbedingt nötig ist, tcp::socket
ist wohl zwar nicht kopierbar aber ich möchte "einfach" nur ein Socket
in einer map erzeugen/speichern.
Hat jemand eine Idee wie man den Socket in die Map bekommt?
Viele Grüße
> Fehler: kein geeigneter Standardkonstruktor verfügbar with> [Protocol=boost::asio::ip::tcp"]
Also mit VC++ funktioniert das. Macht aber natürlich wenig Sinn, ein
Objekt im lokalen Kontext zu erstellen und dann in den pair Konstruktor
zu moven, wodurch das Objekt ungültig wird. Er versucht dann, das Objekt
neu mit einem Standardkonstruktor zu konstruieren und das schlägt
natürlich fehl. Versuch mal
Versuche mal das boost ip::tcp::socket objekt auf dem heap zu
alloziieren, und verwende shared pointer um das kopieren zu vermeiden
ohne aufwand mit der Speicherverwaltung zu bekommen. Ungetestet:
Felix U. schrieb:> Er versucht dann, das Objekt> neu mit einem Standardkonstruktor zu konstruieren
Wenn das so wäre, wären alle nicht-kopierbaren Objekte ja auch nicht
move-bar. Der move-Konstruktor ruft nicht den Standardkonstruktor auf,
sondern hinterlässt das Original-Objekt in einem "leeren" Zustand
(typischerweise einer, sodass der Destruktor gar nichts tut).
Daniel A. schrieb:> verwende shared pointer um das kopieren zu vermeiden
Eine Socket-Klasse enthält vermutlich nur einen Integer. Den zu kopieren
geht schneller als eine Heap-Allokation. Insbesondere der Move
Construktor ist ja darauf ausgelegt, möglichst schnell zu sein. Und dann
auch noch shared_ptr, der nochmal extra langsam ist?! Da doch wenigstens
unique_ptr.
Dr. Sommer schrieb:> Der move-Konstruktor ruft nicht den Standardkonstruktor auf
Das sollte so sein, und in VC++ funktioniert es ja auch. Das ist aber
die einzige logische Erklärung für mich, warum er sich an der Stelle
über einen gelöschten Standardkonstruktor beschweren könnte.
Felix U. schrieb:> Das ist aber> die einzige logische Erklärung für mich, warum er sich an der Stelle> über einen gelöschten Standardkonstruktor beschweren könnte.
Es wird ja nichtmal klar gesagt, welcher Standardkonstruktor hier
gemeint ist. Es ist auch nicht gesagt, dass überhaupt die gezeigte
Stelle relevant ist. Es kann gut sein, dass std::map irgendwo noch
Instanzen anlegt. Aber ohne vollständige Fehlermeldung kann man dazu nix
sagen. Ist hier ja so üblich, mit Informationen zu geizen.
Hier ein Beispiel: https://ideone.com/XgnGwm
Der Standard-Konstruktor von X existiert nicht und wird auch nicht
aufgerufen. Es wird nur beim moven der Move-Konstruktur aufgerufen, und
2x der Destruktor. Angenommen das m_x ist der Socket-File-Handle, dann
könnte man den im Destruktor schließen sofern es nicht -1 ist.
Dr. Sommer schrieb:> Daniel A. schrieb:>> verwende shared pointer um das kopieren zu vermeiden> Eine Socket-Klasse enthält vermutlich nur einen Integer.
Das ist Spekulation zur Implementation einer API. Boost enthält hier
noch etwas mehr als nur dass, aber diese Implementationsdetails sind
irrelevant. Shared Pointer sind auch nur Reference Counting und das
Kopieren eines Pointers, was immernoch sehr schnell geht. Insgesamt wäre
es also verfrühte Optimierung mit ungewissem Ausgang, wenn es den ginge.
> Den zu kopieren geht schneller als eine Heap-Allokation.> Insbesondere der Move Construktor ist ja darauf ausgelegt,> möglichst schnell zu sein.
Die API hat hier aber keinen copy constructor und ist auch nicht
moveable, dein Vorschlag ist somit garnicht umsetzbar und damit
irrelevant. Das Objekt zu Kopieren wäre ohnehin ein kaputtes Design, da
es vom selben Socket logisch gesehen immer nur eine Instanz geben kann.
Ein gutes Programmdesign ist wichtiger, als ein paar theoretisch
womöglich verlorene CPU Zyklen, insbesondere hier wo es nicht ins
Gewicht fällt.
Hallo danke,
Irgendwie sind nun die Fehler bei beiden Varianten identisch da hatte
ich einen Fehler gemacht also bei der Variante emplace und der Variante
insert tritt folgender identischer Fehler auf:
1
C:\Visual Studio 2015.3\VC\include\tuple:1180: Fehler: C2512: "boost::asio::basic_stream_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<Protocol>>::basic_stream_socket": Kein geeigneter Standardkonstruktor verfügbar
2
with
3
[
4
Protocol=boost::asio::ip::tcp
5
]
Und der gleiche Fehler auch bei der Variante Felix U. (ubfx):
Asio schrieb:> Das funktioniert, allerdings bekomme ich dann bei anderen Funktionen> eine Fehlermeldung:> socket_map[123].available();> C2039 available ist kein Element von "std::shared_ptr
Man muss den Pointer dann vor der Verwendung noch Dereferenzieren, also
-> statt .
Asio schrieb:> Ich bin nicht mal sicher ob das move unbedingt nötig ist, tcp::socket> ist wohl zwar nicht kopierbar aber ich möchte "einfach" nur ein Socket> in einer map erzeugen/speichern.>> Hat jemand eine Idee wie man den Socket in die Map bekommt?
Wozu willst Du das überhaupt tun? Wenn Dein Funktionsname korrekt ist
("session"), ist der Socket am Ende der Funktion sowieso nutzlos, also
warum ihn erst noch in irgendeine Map moven?
Ansonsten könnte die von Mapper bemängelte Verwendung des [] Operators
eventuell funktionieren, wenn man der Map noch einen eigenen Allokator
spendierd. Allerdings (Zitat MS): "Writing and using your own allocator
class is an advanced C++ topic." :)
Ist dann der Socket auch nach verlassen der Funktion noch vorhanden (in
der Map) oder nur ein Zeiger auf den ehemaligen Ort in der Funktion?
Aus Interesse, gibt es auch eine Lösung bei der "ganz normal" die
Asiodinge ohne * und -> angesprochen werden?
Mapper schrieb:> Mit find() funktioniert es.
Wie kann man mit find() ein Socket in der Map erzeugen?
guest schrieb:> Wozu willst Du das überhaupt tun? Wenn Dein Funktionsname korrekt ist> ("session"), ist der Socket am Ende der Funktion sowieso nutzlos, also> warum ihn erst noch in irgendeine Map moven?
Eine Serveranwendung soll eine Kommunikation zwischen Clients
ermöglichen die nach Verbindungsabbruch per gemeinsamer ID über den
Server wiederhergestellt werden kann.
Die read() und write() Funktionen für die unterschiedlichen Sockets
sollen also in gleichen Funktionen/Threads nutzbar sein (um dort zu
kommunizieren) und sich abwechseln können, zB der Server erhält Daten
per read(socket_A) von Client und sendet an anderen Client
write(socket_B).
Asio schrieb:> Mapper schrieb:>> Mit find() funktioniert es.> Wie kann man mit find() ein Socket in der Map erzeugen?
Die Frage verstehe ich nicht. Natürlich kann man das nicht.
Mein Hinweis bezog sich auf deinen ursprünglichen Code wo der Fehler in
der Zeile
> acceptor.accept(socket_map[123]);
lag.
Wie man einen Socket in der Map erzeugt zeigst du doch selber wunderbar
in der Zeile darüber.
Mapper schrieb:> Mein Hinweis bezog sich auf deinen ursprünglichen Code wo der Fehler in> der Zeile
verstanden
Mapper schrieb:> Wie man einen Socket in der Map erzeugt zeigst du doch selber wunderbar> in der Zeile darüber.
Das was ich zeige funktioniert ja allerdings nicht und erzeugt den
genannten Fehler.
Funtionieren tut nur die Variante mit shared_ptr von Daniel Abrecht wo
man dann mit * und -> arbeiten muss.
Asio schrieb:> Mapper schrieb:>> Wie man einen Socket in der Map erzeugt zeigst du doch selber wunderbar>> in der Zeile darüber.>> Das was ich zeige funktioniert ja allerdings nicht und erzeugt den> genannten Fehler.
Doch es funktioniert. Der Fehler ist in der Zeile darunter.
> Funtionieren tut nur die Variante mit shared_ptr von Daniel Abrecht wo> man dann mit * und -> arbeiten muss.
Das funktioniert, weil std::shared_ptr einen default constructor hat.
Das Problem ist, dass der []-operator ggf. ein neues Objekt in die Map
einfügt, weil er immer eine Referenz zurückgibt. Ist kein Eintrag für
[123] vorhanden, erzeugt die map ein neues Objekt und liefert eine
Referenz darauf zurück. Das kann dann auch mit Zeigern ggf. ein nicht
gültiger sein, so dass eine unbesehene Benutzung dann abschmirgelt.
Fazit: Du willst mit find suchen, schauen dass der iterator nicht
map.end() ist, und nur dann ggf. dereferenzieren.
Asio schrieb:> Ist dann der Socket auch nach verlassen der Funktion noch vorhanden (in> der Map) oder nur ein Zeiger auf den ehemaligen Ort in der Funktion?
Der Socket ist nach der Funktion dann noch in der Map vorhanden. Das ist
ja das praktische bei den Smart Pointern. Bei shared_ptr wird bei jeder
Kopie die du von dem Pointer erzeugst ein Zähler hochgezählt. Nachdem du
den Pointer in die Map kopiert hast ist der Zähler bei 2. Wird ein
shared_ptr Objekt zerstört, wie das lokale Objekt am Ende der Funktion,
wird der Zähler um eins verringert. Erst wenn der Zähler auf 0 ist wird
das eigentlich gespeicherte Objekt, also hier der Socket, gelöscht.
Fantastisch gute Sache! Jetzt hab ich erst geschnallt das der Fehler vom
Zugriff gekommen ist denn der Compiler hat bei mir keine explizite
Markierung im Code gezeigt. Dann ist die Variante von Felix U doch
effektiv:
Direktes Erstellen:
map.insert(std::make_pair(123, tcp::socket(ioservice)));
Zugriff:
map.find(123)->second
Sehr schöne Sache.
Heiko L. schrieb:> schauen dass der iterator nicht> map.end() ist, und nur dann ggf. dereferenzieren.
map.end() zum durschleifen der Keys ber ok? So schleife ich in der Regel
die Keys durch:
for (auto i(map.begin()); i != map.end(); ++i) {key=i->first}
Asio schrieb:> Zugriff:> map.find(123)->second
Ich würde eher zu
map.at(123)
raten. Das ist fast wie die Variante über map[123], werden hier keine
neuen Elemente angelegt weshalb es wie bei find auch keinen Fehler geben
sollte. Im Gegensatz zu find gibt es allerdings eine exception, wenn du
versuchst auf ein ungültiges Element zuzugreifen, statt undefiniertes
Verhalten. Dazu ist es auch weniger Tipparbeit (kein ->second
notwendig).
Asio schrieb:> map.end() zum durschleifen der Keys ber ok? So schleife ich in der Regel> die Keys durch:> for (auto i(map.begin()); i != map.end(); ++i) {key=i->first}
So ist es gedacht. Beachte, dass in dem Fall wo i == map.end() ist die
Schleife abgebrochen wird und nicht nochmal versucht wird über i->first
auf irgendwelche Daten zuzugreifen. Der Iterator der gleich map.end()
ist, enthält nämlich keine Daten mehr und zeigt nur das Ende an.
Asio schrieb:> Direktes Erstellen:> map.insert(std::make_pair(123, tcp::socket(ioservice)));
Das müsste eigentlich auch gehen, und weniger kopieren/verschieben:
1
map.emplace(123,tcp::socket(ioservice));
Asio schrieb:> So schleife ich in der Regel die Keys durch:> for (auto i(map.begin()); i != map.end(); ++i) {key=i->first}
Der moderne C++er macht's so:
1
for(auto&it:map){// it steht für "item", nicht für "iterator"
2
// falls ein eigener Name für den Key gewünscht ist: