probleme mit Vector



  • Hallo zusammen,
    ich bin noch recht neu in der Programmierung mit C++...

    Ich versuche eine Klasse in ein Vector zu packen.

    class Clients
    {
    };
    

    In der main.cpp hab ich:

    std::vector<Clients> clients;
    

    so... auf folgenden Wegen habe ich es probiert und mir kamen dann auch Fehlermeldungen:

    1:

    Clients *c = new Clients();
    clients.push_back(c);
    -------------------------------
    error C2664: 'std::vector<_Ty>::push_back': Konvertierung des Parameters 1 von 'Clients *' in 'const Clients &' nicht möglich
    

    2:

    Clients *c = new Clients();
    clients.push_back(&c);
    -------------------------------
    error C2664: 'std::vector<_Ty>::push_back': Konvertierung des Parameters 1 von 'Clients **' in 'const Clients &' nicht möglich
    

    Kann mir jemand sagen was ich falsch mache? (google hat mir nicht geholfen.. Hab auch C++ Bücher da die mir nicht wirklich helfen.)

    lg



  • Das muss lauten

    std::vector<Clients*> clients;
    

    Du willst ja nicht Instanzen von Clients speichern sondern nur Zeiger darauf.



  • Warum legst du die Objekte mit new an, wenn du im vector keine Zeiger verwendest? (Denk dran das zu jedem new ein delete gehört).

    Üblicherweise arbeitet man hier so:

    clients.push_back(Clients());
    
    // oder
    
    Clients c;
    clients.push_back(c);
    


  • Vielleicht einen std::vector<Client*> ?



  • std::vector<Clients> clients;
    Clients c;
    clients.push_back(c);
    


  • wow... so einfach ;)... Vielen Dank :)...

    Ich möchte 50x die Klasse Client anlegen (da wird jeweils 1 Socket übergeben)... Damit wenn neue Verbindungen kommen (habe auch einen Server mit eingehenden Verbindungen) ich diesen Verbindungen einen Socket zuordnen kann (so ein Weiterleitungsprinzip)... Muss also immer darauf zugreifen können ;).

    Ich komme größtenteils von Java... Da würde man das mit einem Vector machen.. den man dann in einer for schleife durchlaufen lässt um rauszufinden welcher dieser 50 gerade nichts zu tun hat.



  • JayJayW schrieb:

    Ich versuche eine Klasse in ein Vector zu packen.

    Objekte

    JayJayW schrieb:

    class Clients
    {
    };
    

    In der main.cpp hab ich:

    std::vector<Clients> clients;
    

    Sicher, dass die Klasse nicht Client heißen sollte?

    JayJayW schrieb:

    Clients *c = new Clients();
    clients.push_back(c);
    

    Wie kommst du auf new ? C++ ist nicht Java.

    Man speichert die Objekte direkt, wenn deren spätere Adresse keine Rolle spielt.
    vector kopiert die Objekte beim Wachsen (z. B. push_back ) in einen neuen Speicherbereich, also ändern sich die Adressen der enthaltenen Objekte. Das ist nur dann ein Problem, wenn das Programm irgendwo anders Zeiger oder Referenzen auf Objekte in dem vector speichert und erwartet, dass diese (nach weiteren push_back s) gültig bleiben.

    std::vector<Client> clients;
    clients.push_back(Client());
    

    Damit sich die Adressen der Objekte nicht ändern, kann man Indirektion verwenden. Anstelle der Objekte selbst speichert man im vector nur Zeiger auf die Objekte. Die tatsächlichen Objekte liegen irgendwo anders und bleiben da, solange der Zeiger existiert. So ein Objekt wird mit new erstellt und dann einem unique_ptr übergeben. Wird der Zeiger zerstört, zerstört er auch das eigentliche Objekt.

    std::vector<std::unique_ptr<Client>> clients;
    clients.push_back(std::unique_ptr<Client>(new Client));
    

    Rohe Zeiger drücken niemals ein Besitzverhältnis aus, das ist in C++ so nicht vorgesehen. Wird zwar oft gemacht, ist aber falsch:

    Client *c = new Client;
    


  • ok also ich hoffe ich habe das richtig verstanden... Ich muss:

    std::vector<std::unique_ptr<Client>> clients;
    clients.push_back(std::unique_ptr<Client>(new Client));
    

    benutzen damit die Klassen im selben Speicherbereich bleiben und ich immer wieder darauf zugreifen kann... Nun kann ich auch mit:

    for (vector<std::unique_ptr<Client>>::iterator it = clients.begin(); it!=clients.end(); ++it) 
    {
        Clients c = *it;
    }
    

    darauf zugreifen?



  • JayJayW schrieb:

    benutzen damit die Klassen im selben Speicherbereich bleiben

    Objekte

    JayJayW schrieb:

    for (vector<std::unique_ptr<Client>>::iterator it = clients.begin(); it!=clients.end(); ++it) 
    {
        Clients c = *it;
    }
    

    Das legt eine Kopie namens c an. Was du aber wahrscheinlich willst, ist eine Referenz Client &c = *it .



  • Jetzt bekomme ich:

    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    #include <winsock.h>
    
    #pragma comment(lib, "Iphlpapi.lib")
    #pragma comment(lib, "ws2_32.lib")
    
    #include "Clients.h"
    
    using namespace std;
    
    std::vector<std::unique_ptr<Clients>> clients; 
    
    Zeile 19: clients.push_back(std::unique_ptr<Clients>(new Clients()));
    
    main.cpp(19) : error C2039: 'unique_ptr': Ist kein Element von 'std'
    main.cpp(19) : error C2065: 'unique_ptr': nichtdeklarierter Bezeichner
    main.cpp(19) : error C2275: 'Clients': Ungültige Verwendung dieses Typs als Ausdruck
    main.cpp(19) : error C2143: Syntaxfehler: Es fehlt ';' vor '>'
    main.cpp(19) : error C2059: Syntaxfehler: '>'
    

    Java ist doch etwas einfacher :).. Ich kann aber leider nicht auf Java zurück greifen.



  • Also ich habe das Problem nun lösen können indem ich das weg gelassen habe (ich hoffe das macht nichts)...

    Ich poste hier mal etwas mehr Code:

    main.cpp

    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    #include <winsock.h>
    
    #pragma comment(lib, "Iphlpapi.lib")
    #pragma comment(lib, "ws2_32.lib")
    
    #include "Clients.h"
    #include "main.h"
    
    using namespace std;
    
    SOCKET server;
    //vector<unique_ptr<Clients>> clients; 
    vector<Clients> clients;
    
    SOCKET sock[50];
    HANDLE threads[50];
    
    int pos = 0;
    
    DWORD WINAPI HandleClients(LPVOID data)
    {
    	int cur = reinterpret_cast<int>(data);
    
    	string receive = "";
    	receive = receiveFromSock(sock[cur]);
    
    	if(receive.find("<--><-->..ADCLIENT..<--><-->") != -1)
    	{
    		Clients c = Clients(sock[cur]);
    
    		clients.push_back(c);
    
    		DWORD ff;
    		GetExitCodeThread(threads[cur],&ff);
    		ExitThread(ff);
    		return 0;
    	}
    
    	Clients c = fetchClient();
    
    	send(c.GetSocket(),receive.c_str(),receive.length(),0);
    
    	receive = receiveFromSock(c.GetSocket());
    
    	send(sock[cur],receive.c_str(),receive.length(),0);
    
    	closesocket(sock[cur]);
    
    	c.SetBusy(false);
    
    	DWORD ff;
    	GetExitCodeThread(threads[cur],&ff);
    	ExitThread(ff);
    	return 0;
    }
    
    Clients fetchClient()
    {
    	bool found = false;
    
    	while(!found)
    	{
    		for (vector<Clients>::iterator it = clients.begin(); it!=clients.end(); ++it)
    		{
    			Clients &c = *it;
    
    			if(c.GetSocket() == INVALID_SOCKET)
    			{
    				clients.erase(it);
    				continue;
    			}
    
    			if(!c.IsBusy())
    			{
    				c.SetBusy(true);
    				found = true;
    				return c;
    			}
    		}
    
    		if(!found)
    		{
    			Sleep(5000);
    		}
    	} 
    }
    
    int startServer()
    {
    
    	unsigned long id;
    	while(TRUE)
    	{
    		cout << "warte\n";
    
    		sock[pos] = accept(server,(LPSOCKADDR)&serv_addr2,&size);
    
    		threads[pos] = CreateThread(NULL,0,&HandleClients,(LPVOID)pos,0,&id);
    
    		Sleep(100);
    		if(pos == 50)
    		{
    			pos = 0;
    		}else{
    			pos++;
    		}
    	}
    
    	return 1;
    }
    
    int main()
    {
    	startServer();
    
    	return 0;
    }
    

    ----------------------------------------------------------------------------
    Clients.h

    #pragma once
    
    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <winsock.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    using namespace std;
    
    class Clients
    {
    public:
    	Clients::Clients(SOCKET s);
    	Clients::~Clients();
    
    	SOCKET GetSocket();
    
    	void SetBusy(bool value);
    	bool IsBusy();
    
    	SOCKET sock;
    	bool busy;
    };
    
    Clients::Clients(SOCKET s)
    {
    	printf("SOCKET: %s\n",s.ToString());
    	this->sock = s;
    	this->busy = false;
    }
    Clients::~Clients()
    {
    	closesocket(this->sock);
    }
    
    SOCKET Clients::GetSocket()
    {
    	return this->sock;
    }
    
    void Clients::SetBusy(bool value)
    {
    	this->busy = value;
    }
    bool Clients::IsBusy()
    {
    	return this->busy;
    }
    

    Es geht darum das ich einfach z.B. 10 Grundsockets habe an die ich alle Anfragen an feste Verbindungen weiterleiten muss (Clients) und deren Antwort an normale Verbindungen die kommen und gehen...

    Mein Problem ist jetzt folgendes... Wenn ich:

    Clients c = fetchClient();
    

    aufrufe bekomme ich zwar ein Client als Rückgabewert, welcher aber nicht in der Lage ist, zu senden und zu empfangen.

    Ich hoffe ihr wisst Rat 😕

    lg



  • Ich weiß gar nicht, wo ich anfangen soll. Dein Code hat so viele Probleme.

    main.cpp:
    - Zeilen 8, 9: Das linken von Libs gehört einfach nicht in den Code. Mach das in den Einstellungen.
    - Zeilen 31, 108: Niemand garantiert dir, dass void* >= int ist. Das ist zwar auf x86-Systemen der Fall, aber auf sowas würde ich mich niemals verlassen. Du solltest die Adresse von pos übergeben.
    - Zeilen 38, 48, 67: Du kopierst einen Client, das ist garantiert nicht, was du möchtest. Du solltest deine Client-Klasse nicht-kopierbar machen durch privaten Copy-Ctor und Copy-Assignment-Op.
    - Zeilen 111-116: Wie wäre es mit:

    ++pos %= 50;
    

    Clients.h:
    - Die Klasse sollte immer noch "Client" heißen.
    - Zeile 29: printf ist C. Ich dachte wir machen C++?
    - Zeile 29: Ich kann mir nicht vorstellen, dass SOCKET eine .ToString()-Methode hat.
    - Keine Initialisierungsliste im Konstruktor verwendet.
    - this-> zum Zugriff auf Klassenmember kannst du weglassen. Das braucht man so gut wie nie.

    Generelles:
    - Du scheinst das C++-Objektmodell nicht verstanden zu haben.
    - Du vermischst überall C++ mit C und WinAPI. Dadurch ist dein Code unportabel und unwartbar.
    - Fehlerbehandlung hast du (so gut wie) keine.
    - Was Thread-Safety angeht, hab ich mir deinen Code jetzt gar nicht erst angesehen. In der Hinsicht dürfte so ziemlich alles explodieren.

    Und nebenbei hab ich nicht verstanden, was ein "busy"-Client ist.

    Ich fürchte, ein Server ist einfach noch zu viel für dich. Du solltest erstmal ein solides Wissen an Grundlagen haben, bevor du dich an sowas wagst. Sobald du das hast, solltest du außerdem eine Biliothek, etwa boost.asio, SFML oder Poco dafür verwenden. Die kapseln dir den hässlichen Plattform-spezifischen Code weg.

    Und bevor du so einen Server schreibst, schreib erstmal einen Server, der Clients seriell bearbeitet.



  • Wie schon gesagt bin ich ziemlich neu in C++ :D... Aber danke für die Ratschläge ich werde mein Wissen auch noch erweitern... Aber wegen genau diesen Codezeilen bin ich zu C++ gekommen. Daher brauche ich auch dringend die Lösung dieses Problems ;).

    Ales funktioniert bis auf die Client/Vector Geschichte.

    Ein Busy-Client ist ein Client welche gerade eine Anfrage bearbeitet und deshalb momentan nicht zur Verfügung steht.

    Kann mir jemand bei meinem Clients/Vector Problem helfen? ;).

    lg


Anmelden zum Antworten