Problem bei Funktion für Stringverarbeitung



  • Dafür gibt es dann std::to_string.



  • Von to_string wusste ich nichts, deswegen hab ich den stringstream benutzt.
    Jedenfalls scheint es als hätte nur die Zeile

    str.erase( 0, str.size() - nMaxChars );
    

    das Problem mit den Zeilenumbrüchen gelöst, auch wenn ich den Grund nicht erkenne.



  • Folgendes:

    &*str.end() - nMaxChars
    

    erzeugt UB (str.end() ist nicht dereferenzierbar). MSVC haut einem im Debug-Modus dafür einen assert um die Ohren.

    str.c_str() + str.size() - nMaxChars
    

    wär jetzt mein Ansatz. Geht sogar in C++03.



  • untester schrieb:

    Och nö.

    Autsch, hast Recht, das bearbeiten des Strings ist völlig überflüssig. Da habe ich wieder zu genau hingeschaut....



  • Es geht auch ohne string oder gar stringstream.

    //nMaxChars ist die maximale Länge des Textes von hWnd
    template <class myType>
    BOOL AddWindowText(HWND hWnd,myType text,  const int nMaxChars, bool breakLine=true)
    {
        char* buf=new char[nMaxChars+1]; //GetWindowText fügt eine 0 am Ende hinzu
    
        GetWindowText(hWnd, buf, nMaxChars+1);
        strncat(buf, text, strlen(buf)<nMaxChars?nMaxChars-strlen(buf):0);
        if( breakLine )
          strncat(buf, "\r\n", strlen(buf)<nMaxChars-1?2:0);
    
        BOOL r = SetWindowText(hWnd, buf);
        delete [] buf;
        return r;
    }
    


  • Wutz, was soll der Blödsinn? Wer zum Teufel arbeitet hier mit new / delete ?

    Hier würde sich ein Start/End Iteratorenpaar besser machen.
    Edit²: Weil unten schon steht, dass er ja irgendwie jeden Typen ausgeben lassen können will, muss man doch per Referenz o.ä. übergeben.

    Ich benutz einen stringstream um jeden Datentyp zu einem String umzuwandeln.

    Edit: Habe ich übersehen... das ist was anderes. Das geht dann tatsächlich nicht ohne Stringstream, wenn diese Datentypen möglicherweise nur den operator<< überladen.



  • Reg dich ab.
    Set/GetWindowText ist eindeutig WinAPI, und die arbeiten ausschließlich mit char/TCHAR.



  • Wutz schrieb:

    Set/GetWindowText ist eindeutig WinAPI, und die arbeiten ausschließlich mit char/TCHAR.

    Ja, aber das geht trotzdem mit C++-Strings. Da braucht man nicht RAII zu vernachlässigen. 🙂

    Ich werfe mal eine neue Version in den Ring:

    template <class myType>
    BOOL AddWindowText( HWND hWnd,
                        myType const& text,
                        std::size_t nMaxChars,
                        bool breakLine = true )
    {
        std::string Buffer( nMaxChars + 1 );
    
        GetWindowText(hWnd, &Buffer[0], Buffer.length());
    
        std::ostringstream stream( Buffer );
        stream << text;
    
        if( breakLine )
            stream << "\r\n";
    
        std::string rval = stream.str();
        char const* begin = rval.c_str():
    
        if( rval.length() > nMaxChars )
    		begin += rval.length() - nMaxChars - 1;
    
        return SetWindowText(hWnd, begin);
    }
    


  • Ein anderes kleines Problem ist die to_string Funktion. Wieso muss ich ein int zu long double casten beim übergeben und wieso hat to_string bei mir nur 3 varianten die alle kein int nehmen, wie es hier zu sehen ist: http://www.cplusplus.com/reference/string/to_string/?kw=to_string

    Außerdem würde ich gern den << Operator für HWND überladen, aber es geht nicht.

    HWND operator<<(HWND hWnd, const char* text)
    {
    	AddWindowText(hWnd, text);
    	return hWnd;
    }
    

    Da kommt nur die Meldung dass ein Operator der kein Member ist einen Klassen- oder Enumerationstyp erfordert. Geht der Operator also nur als Klassenmember?



  • hat keine ne idee?



  • Wutz schrieb:

    Set/GetWindowText ist eindeutig WinAPI, und die arbeiten ausschließlich mit char/TCHAR.

    Och, ein std::vector<char/TCHAR> tut es auch, vector<...>.data() gibt es schon in VS 2010.

    Das Problem: Ist das Window dann owner des Textes?

    Wieso muss ich ein int zu long double casten beim übergeben und wieso hat to_string bei mir nur 3 varianten die alle kein int nehmen,

    1.) Es gibt auch eine Ueberladung fuer (in)signed Long Long.
    2.) Du benutzt wahrscheinlich VS 2010.

    Außerdem würde ich gern den << Operator für HWND überladen, aber es geht nicht.

    1.) Tolle Fehlerbeschreibung
    2.) HWND ist wahrscheinlich ein void*, diese ueberladung gibt es wahrscheinlich schon.



  • 1. to_string() hat Überladungen für fast alle arithmetischen Typen, sieht man auch in deinem Link, es gibt auch eine für int.
    2. Operaturüberladungsfunktionen müssen mindestens einen benutzerdefinierten Typen (Klasse, ....) als Argument nehmen (oder zurückgeben?), du kannst keine Version für zwei Pointer schreiben (HWND ist ein Typedef für einen Pointer auf eine struct HWND__ oder mit ähnlichem Namen, weiß ich nicht auswendig).
    So eine Operatorüberladung ist auch schwachsinnig und unintuitiv (?).
    Falls du es doch machen willst, musst du entweder HWND in eine Klasse kapseln (was du schon allein wegen RAII machen solltest!) oder einen std::string als zweites Argument nehmen.



  • Francis123 schrieb:

    Ein anderes kleines Problem ist die to_string Funktion. Wieso muss ich ein int zu long double casten beim übergeben und wieso hat to_string bei mir nur 3 varianten die alle kein int nehmen, wie es hier zu sehen ist: http://www.cplusplus.com/reference/string/to_string/?kw=to_string

    Das leigt daran, dass vor VS2012 mit to_string nur eben die Standard Floatingpoint Zahlen eingebaut waren. to_string ist eigentlich C++11 und war damals im begrenzten Umfang eine kleine Erweiterung von VS2010 (und ich weis nicht welchen Versionen vorher), mit VS2012 wird to_string dann voll unterstützt.



  • Ist es möglich beim Aufrufen einer Funktion die ein Struct erwartet das Struct direkt zu erzeugen ohne vorher eine Variable zu erstellen und diese dann zu übergeben?



  • Meinst du sowas?

    struct foo{};
    ...
    func(foo(a, b, c, d, e, f, g));
    

    ?



  • Ja das meine ich, aber bei mir geht das so nicht weil da nur ein Kopierkonstruktor und ein leerer Konstruktor zur Auswahl stehen.



  • Dann schreibste halt einen benutzerdefinierten Konstruktor!
    Oder du nutzt Aggregat-Initialisierung:

    func({a, b, c, d});
    


  • Ich will bei einem vector mit diesem struct die structs mit push_back einfügen.
    So wie du das geschrieben hast geht es leider nicht. Da steht dann nur es wurde ein Ausdruck erwartet. Geht wohl nur mit einer eigenen Funktion die den vector pointer und die restlichen Daten nimmt.



  • Wutz schrieb:

    Reg dich ab.
    Set/GetWindowText ist eindeutig WinAPI, und die arbeiten ausschließlich mit char/TCHAR.

    Das ist kein Grund, mit new[] / delete[] zu arbeiten. Kannst auch genauso gut

    vector<char> puffer(999);
    eine_C_Funktion(&puffer[0],999);
    

    schreiben. Dann kann es dir gar nicht passieren, delete[] zu "vergessen". Auch wenn du delete[] dort stehen hast, kann ja zwischendurch irgendwo eine Ausnahme fliegen und dann hättest du ein Speicherleck, weil die Ausführung gar nicht erst zum delete[] kommt.

    Ab C++11 ist das auch bei std::string erlaubt, weil garantiert ist, dass die Elemente hintereinander im Speicher stehen. Allerdings muss man sich, wenn man das so in String schreiben lässt, selbst um die Nullterminierung kümmern. Die will man typischerweise nicht mit drin haben und auch den Rest dahinter nicht. Also:

    string s (999);
    eine_C_Funktion(s.data(),999); // ab C++11
    s.erase(find(s.begin(),s.end(),'\0'),s.end());
    

    (ungetestet)

    Merken: new[] und delete[] brauchen wir so gut wie nie mehr.



  • Merken: new[] und delete[] brauchen wir so gut wie nie mehr.

    so gut? 🙂
    Ich meine, wir brauchen seit C++11/14* nicht mal new zu schreiben, vorausgesetzt wir arbeiten brav mit Smart-Pointern.

    Auch wenn du delete[] dort stehen hast, kann ja zwischendurch irgendwo eine Ausnahme fliegen und dann hättest du ein Speicherleck, weil die Ausführung gar nicht erst zum delete[] kommt.

    Wieso erklärst du ihm das? Das weiß er (so hoffe ich) selbst.

    HWND ist wahrscheinlich ein void*, diese ueberladung gibt es wahrscheinlich schon.

    Beides richtig. HWND ist ein HANDLE , was wiederum ein PVOID ist. Und der Ausgabeoperator für void* ist schon überladen (in ostream selbst).

    Die will man typischerweise nicht mit drin haben und auch den Rest dahinter nicht.

    Bei vielen solchen Funktionen ist von vornherein klar, dass '\0' das letzte Zeichen im String ist - daher reicht da meistens auch ein pop_back().
    Und wieso benutzt du nicht die find() -Funktion aus std::string ?

    • make_unique

Anmelden zum Antworten