Call by reference mit std::string



  • Also ich habe paar String-Funktionen in einen Namespace VString das ganze befindet sich in der "fVString.h"

    #ifndef F_VSTRING_H
    #define F_VSTRING_H
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    namespace VString {
    ... bla funktionen ...
    };
    #endif;
    

    Ich Inkludiere "fVString.h" dann in "HTTP_Request.cpp" mehr hab ich bis jetzt nicht gemacht also ich greife noch nicht mal auf die Funktionen zu.



  • drakon schrieb:

    Includeguards bringen in einem solchen Fall nichts. Die verhindern nur, dass ein Header in einer Übersetzungseinheit nicht 2x inkludiert wird.

    Stimmt...


  • Administrator

    @Frido,
    Zeig mal wo und wie du die Funktion void VString::rtrim(std::string&) definierst. Du hast mindestens ein fVString.h , fVString.cpp und HTTP_Request.cpp File. Die Vermutung liegt nahe, dass du die Funktion in fVString.h definierst, wie es bereits drakon erwähnt hat. Dann würde sie in zwei Übersetzungseinheiten, nämlich fVString.cpp und HTTP_Request.cpp definiert werden, wodurch du eine doppelte Definition hast, worüber dein Linker korrekterweise meckert.

    Grüssli



  • ah ok

    Also jetzt geht's. Ich hatte Funktionskopf und den Code der Funktion in der "fVString.h" das wollte er wohl nicht 😛 habs jetzt in .h und .cpp aufgeteilt und siehe da es geht. Ich glaub ich guck mir bei Gelegenheit mal an wie Compiler und Linker arbeiten dann versteh ich den Fehler evt.

    Danke an alle 🙂



  • Frido schrieb:

    ah ok

    Also jetzt geht's. Ich hatte Funktionskopf und den Code der Funktion in der "fVString.h" das wollte er wohl nicht 😛 habs jetzt in .h und .cpp aufgeteilt und siehe da es geht. Ich glaub ich guck mir bei Gelegenheit mal an wie Compiler und Linker arbeiten dann versteh ich den Fehler evt.

    Danke an alle 🙂

    Ja. Das habe ich dir ja schon oben gesagt, dass du die trennen musst. Das es manchmal geht und manchmal nicht liegt wohl daran, dass der Compiler das geinlied hat und manchmal nicht. Dann geht das nämlich auch.

    Der Grund ist ganz einfach. In einem C++ Programm darf man nichts 2x definieren (von dern Sonderfällen von templates usw. mal abgesehen). Du musst also die ODR (one definition rule befolgen). Wenn du jetzt aber eine Definition in einem Header hast und diesen Header dann in verschiedenen Übersetzungseinheiten (.cpp) includest, dann wird der Compiler da in beiden Fällen eigene Defintionen erstellen, welche für sich Ok sind. Wenn jetzt aber der Linker daher kommt und sieht, dass eine Funktion 2x definiert ist, dann gibt das Ärger und meldet dir den obigen Fehler.
    Das Verhalten ist auch verständlich, denn welche Definition soll der Linker denn nehmen, wenn verschiedene Versionen vorliegen? (das sie von dem gleichen Header kommen weiss der Linker ja nicht und daher könnten es komplett unterschiedliche Versionen sein).



  • So jetzt hab ich weitergemacht und das ganze in ne Klasse gepackt jeweils als Statische Methoden.

    Fehler ist der :

    1>Debug\VString.obj : warning LNK4042: object specified more than once; extras ignored
    1>HTTP_Request.obj : error LNK2019: unresolved external symbol "public: static void __cdecl VString::trim(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?trim@VString@@SAXAAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: __thiscall HTTPRequest::HTTPRequest(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int)" (??0HTTPRequest@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@Z)
    1>HTTP_Request.obj : error LNK2019: unresolved external symbol "public: static class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > __cdecl VString::split(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int)" (?split@VString@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@V43@H@Z) referenced in function "public: __thiscall HTTPRequest::HTTPRequest(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int)" (??0HTTPRequest@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@Z)
    1>D:\C++\VreshAdManger\Debug\VreshAdManger.exe : fatal error LNK1120: 2 unresolved externals
    

    VString.h :

    #ifndef VSTRING_H
    #define VSTRING_H
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    class VString {
    
    public:
    
    	static std::vector<std::string> split(const std::string &delimiter,std::string str,int maxparts);
    
    	static void rtrim(std::string &str);
    
    	static void ltrim(std::string& str);
    
    	static void trim(std::string& str);
    
    };
    
    #endif
    

    VString.cpp :

    #include "VString.h"
    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    vector<string> VString::split(const string &delimiter,string str,int maxparts)
    {
    	vector<string> ret;
    	if(delimiter.length() < 1) {
    		ret.insert(ret.end(),str);
    	}
    	else if(delimiter.length() == 1) {
    		size_t lpos = 0;
    		for(size_t i = 0;i < str.length();++i)
    		{	
    			if(maxparts != -1 && ret.size() == maxparts)	{
    				ret.push_back( str.substr(lpos) );
    				break;
    			}
    			if(str[i] == delimiter[0])	{
    
    				ret.push_back( str.substr(lpos , (i - lpos)) );
    				lpos=i+1;
    			}
    		}
    
    	}
    	else	{
    		size_t lpos = 0;
    		while(lpos != string::npos)	{
    			if(maxparts != -1 && ret.size() == maxparts)	{
    				ret.push_back( str.substr(lpos) );
    				break;
    			}
    			size_t tmp = 0;
    			tmp=str.find(delimiter,lpos);
    			ret.push_back( str.substr(lpos , ( (tmp) - lpos)) );
    			lpos= (tmp == string::npos) ? string::npos : (tmp+delimiter.length()) ;
    		}
    	}
    	//nothing splited?
    	if(ret.size() == 0)
    		ret.push_back(str);
    
    	return ret;
    }
    
    void VString::rtrim(string &str)	{
    
    	for(size_t i = (str.length()-1);i > 0; --i)
    	{
    		if(str[i] == ' ') str.erase(i);
    		else break;
    	}
    }
    
    void VString::ltrim(string& str)	{
    
    	for(size_t i = 0;i < str.length(); ++i)
    	{
    		if(str[i] == ' ') str.erase(i,1);
    		else break;
    	}
    
    }
    
    void VString::trim(string& str)	{
    	VString::ltrim(str);
    	VString::rtrim(str);
    }
    

    Hier wird das ganze dann Benutzt :

    #include "HTTP_Request.h"
    #include <iostream>
    #include <string>
    #include <vector>
    #include "VString.h"
    
    HTTPRequest::HTTPRequest(string raw_data,size_t len)
    {
    	if(raw_data.find("GET") != string::npos || raw_data.find("POST") != string::npos)	{	
    
    		headerValid=true;
    		raw_data = raw_data.substr(0,len);
    
    		cout << raw_data << endl;
    
    		vector<string> lines = VString::split("\r\n",raw_data,-1);
    
    		for(size_t i = 0;i < lines.size();++i)
    		{
    			if(lines[i].find("GET") != string::npos)	{	
    				request_data.method=HTTP_METHOD_GET;
    				vector<string> tmp = VString::split(" ",lines[i],-1);
    				cout << " ===== URL =====>>|" << tmp[1] << "|" << endl;
    			}
    			if(lines[i].find("POST") != string::npos)	{	
    				request_data.method=HTTP_METHOD_POST;
    			}
    			if(lines[i].find("User-Agent:") != string::npos)	{	
    				vector<string> tmp = VString::split(":",lines[i],1);
    				VString::trim(tmp[1]);
    				request_data.user_agent = tmp[1];
    			}
    			if(lines[i].find("Accept-Encoding:") != string::npos)	{
    				if(lines[i].find("gzip") != string::npos)
    					request_data.supports_gzip=true;
    				else
    					request_data.supports_gzip=false;
    			}
    
    		}
    
    		cout << "UA:" << request_data.user_agent << endl;
    		cout << "M:" << request_data.method << endl;
    		cout << "Gzip:" << (request_data.supports_gzip ? "Yes" : "No" ) << endl;
    		//request_data.
    
    	}
    	else
    	{
    		headerValid=false;
    	}
    }
    

    Das tolle ist es ging alles bis ich bei VStrin::split den letzten Parameter hinzugefügt hab, also int maxparts. Ich hoffe ich hab das jetzt so einigermaßen verständlich geschildert.

    greets Frido



  • Frido schrieb:

    So jetzt hab ich weitergemacht und das ganze in ne Klasse gepackt jeweils als Statische Methoden.

    Nur mal so nebenbei: Warum? Welchen Sinn macht es eine Klasse nur mit statischen Methoden zu definieren? Das macht nur in Programmiersprachen Sinn, die nichts besseres anzubieten haben. Aber in C++ gibt es Namespaces.



  • Ich hab das nur gemacht weil fast der selbe Linker Fehler kam als ich das in einen Namespace hatte ... da Dachte ich mir evt. geht's ja mit ner Klasse und Statischen methoden das ging dann auch bis ich wie oben erwähnt den Letzten Parameter hinzugefügt hab ...

    greets Frido

    Edit: Jetzt hab ich wieder in einen Namespace und siehe da kein Fehler. Aber WARUM ??? Ich versteh echt garnix mehr 😞 Ich mein das mit den Statischen Methoden müsse doch auch gehen... 😞

    Edit² : Langsam glaub ich es liegt am Linker ... wenn ich alles was im Ordner Debug ist lösche geht's :o



  • tntnet schrieb:

    Frido schrieb:

    So jetzt hab ich weitergemacht und das ganze in ne Klasse gepackt jeweils als Statische Methoden.

    Nur mal so nebenbei: Warum? Welchen Sinn macht es eine Klasse nur mit statischen Methoden zu definieren? Das macht nur in Programmiersprachen Sinn, die nichts besseres anzubieten haben. Aber in C++ gibt es Namespaces.

    Namespaces gibt es in Java oder C# auch. Aber in C++ gibt es freie Funktionen (und Namespaces) 😉



  • hustbaer schrieb:

    tntnet schrieb:

    Frido schrieb:

    So jetzt hab ich weitergemacht und das ganze in ne Klasse gepackt jeweils als Statische Methoden.

    Nur mal so nebenbei: Warum? Welchen Sinn macht es eine Klasse nur mit statischen Methoden zu definieren? Das macht nur in Programmiersprachen Sinn, die nichts besseres anzubieten haben. Aber in C++ gibt es Namespaces.

    Namespaces gibt es in Java oder C# auch. Aber in C++ gibt es freie Funktionen (und Namespaces) 😉

    Danke für die Korrektur. Du hast natürlich recht 🙂 .

    Frido schrieb:

    Edit: Jetzt hab ich wieder in einen Namespace und siehe da kein Fehler. Aber WARUM ??? Ich versteh echt garnix mehr 😞 Ich mein das mit den Statischen Methoden müsse doch auch gehen... 😞

    Edit² : Langsam glaub ich es liegt am Linker ... wenn ich alles was im Ordner Debug ist lösche geht's :o

    Ich versuche es mal möglichst kurz zu erklären.

    Wenn der Compiler eine Implementierung einer Funktion sieht, dann implementiert er die Funktion halt. Die steht dann in der Objektdatei. Wenn Du 2 Source-Dateien hast, dann hast Du auch 2 Objektdateien. Und wenn Du die Funktion im Header definiert hast, dann findet der Linker sie in beiden Objektdateien. Dann kommt es zum Linkerfehler, dass die Funktion 2 mal definiert ist.

    Wenn der Compiler im Header eine Funktionsdeklaration sieht, also eine Funktion ohne Body, dann merkt er sich erst mal einfach, dass er die Funktion braucht. Entweder der Compiler sieht die Implementierung der Funktion später oder es bleibt zunächst als unaufgelöstes Symbol in der Objektdatei. Der Linker kümmert sich dann darum, dass das Symbol gebunden wird.

    Ein wenig anders verhält es sich, wenn eine Funktion inline definiert ist oder ein Template ist. Inlinen kann der Compiler nur, wenn er die Funktionsdefinition auch sieht. Daher muss die Funktionsdefinition gleich erfolgen. Der Compiler exportiert diese Funktion aber nicht, da er den Body ja nur zum inlinen braucht. Der Linker sieht die Funktion dann auch nicht und es kommt zu keinen Mehrfachdefinitionen.

    Ein Template ist im Prinzip nur eine Bauanleitung für den Compiler. Auch hier wird kein externes Symbol erzeugt und daher ist es auch hier wieder kein Problem, wenn die Definition im Header erfolgt.

    Alles klar?


Anmelden zum Antworten