C++ String-Klasse selbst schreiben

ExperienZ

Newbie
Registriert
Juni 2017
Beiträge
1
Guten Abend,

Ich soll für die Uni derzeit die String-Klasse "nachahmen". Dabei soll ich sowohl eine Klasse "String2", als auch eine Klasse "CharListenKnoten" schreiben, wobei in einem String-Objekt nur ein Pointer auf den ersten CharListenKnoten dieses Strings sein soll und in den CharListenKnoten-Objekten sind die einzelnen Buchstaben, als Einfach-verkettete Liste eingespeichert.
C++:
//CharListenKnoten.h:
class CharListenKnoten
{
private:
    char cont;
    CharListenKnoten* next;

public:
    CharListenKnoten(char cont_in, CharListenKnoten* next_in);

    CharListenKnoten* get_next();
    void set_next(CharListenKnoten* next_in);
    char get_cont();
    void set_cont(char cont_in);
};

//CharListenKnoten.cpp:

#include "CharListenKnoten.h"

CharListenKnoten::CharListenKnoten(char cont_in, CharListenKnoten* next_in)
{
    cont = cont_in;
    next = next_in;
}
void CharListenKnoten::set_next(CharListenKnoten* next_in)
{
    next = next_in;
}
CharListenKnoten* CharListenKnoten::get_next()
{
    return this->next;
}
char CharListenKnoten::get_cont()
{
    return this->cont;
}
void CharListenKnoten::set_cont(char cont_in)
{
    cont = cont_in;
}

//MyString.h:
#include "CharListenKnoten.h"
#include <string>

class MyString2
{
private:
    CharListenKnoten* anker;

    void append_internal(char p_data);

public:
    CharListenKnoten* get_anker();
    void set_anker(CharListenKnoten* anker_in);

    MyString2(CharListenKnoten* anker_in);
    MyString2(std::string input_string, CharListenKnoten* anker_in);
};

//MyString2.cpp:
#include "MyString2.h"
#include <iostream>
CharListenKnoten* MyString2::get_anker()
{
    return this->anker;
}
void MyString2::set_anker(CharListenKnoten* anker_in)
{
    anker = anker_in;
}
MyString2::MyString2(CharListenKnoten* anker_in)
{
    set_anker(anker_in);
}
void MyString2::append_internal(char p_data)
{
    CharListenKnoten* input = &CharListenKnoten(p_data, nullptr);
    if (get_anker() == nullptr)
        set_anker(input);
    else
    {
        CharListenKnoten* hilfe = anker;
        while (hilfe->get_next() != nullptr)
        {
            hilfe = hilfe->get_next();
            std::cout << "1";
        }
        hilfe->set_next(input);
    }
    std::cout << this->anker->get_cont();
}
MyString2::MyString2(std::string input_string, CharListenKnoten* anker_in)
{
    anker = anker_in;
    for (int i = 0; i < input_string.length(); i++)
    {
        this->append_internal(input_string.at(i));
    }
}

In einem Testprogramm versuche ich nun einen "echten" String in ein "String2" einzulesen:
C++:
#include <iostream>
#include "MyString2.h"

int main()
{
    std::string input;
    std::cout << "Testinput: ";
    std::getline(std::cin, input);
    
    MyString2 test = MyString2(input, nullptr);

    std::cout << "Anker: " << test.get_anker()->get_cont();
}
Allerdings scheint es, als würde nach jedem Aufruf von append_internal() der Anker gelöscht werden, hier die Kommandozeile:

Testinput: Hallo
HalloAnker: ╠


Ich würde mich freuen, wenn mir einer von euch etwas unter die Arme greifen könnte.
LG
 
Zuletzt bearbeitet:
Code:
<source>: In member function 'void MyString2::append_internal(char)':
<source>:45:62: error: taking address of rvalue [-fpermissive]
   45 |   CharListenKnoten* input = &CharListenKnoten(p_data, nullptr);
      |                                                              ^

Was für einen Compiler verwendest du, dass dieser Code kompiliert? Das ist nämlich kein legaler Code. Du darfst nicht die Adresse von einem temporären Objekt nehmen und in einen Pointer speichern. Wenn dann musst du hier mit new ein neues Objekt am Heap anlegen (und am Ende wieder freigeben).

Edit:
@new Account() Linked lists mit std::unique_ptr sind etwas tricky.

Gruß
BlackMark
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: new Account()
Nein, hätte er nicht. Das Problem entsteht durch die rekursive destructor chain. Wenn man raw pointer verwendet kann man das Problem ganz leicht durch einen loop im destructor lösen. Mit unique_ptr kann man es durch einen custom deleter lösen.

Und er sollte definitiv memory leaks nicht in Kauf nehmen. Eine linked list die memory leaked ist in meinen Augen einfach nur falsch.

Gruß
BlackMark
 
BlackMark schrieb:
Wenn man raw pointer verwendet kann man das Problem ganz leicht durch einen loop im destructor lösen. Mit unique_ptr kann man es durch einen custom deleter lösen.
Also hat ers doch ;)

Auch mit unique_ptr kannst du einfach eine Loop verwenden (wie dein SO link auch zeigt)
 
new Account() schrieb:
Also hat ers doch
Von welchem Problem reden wir? Ich dachte es geht um das Problem eines stack-overflows. Das hat er nicht mit raw pointer. Das Problem von memory leaks hat er natürlich schon.

new Account() schrieb:
Auch mit unique_ptr kannst du einfach eine Loop verwenden (wie dein SO link auch zeigt)
Ja, geht auch. Finde den custom-deleter zwar schöner, aber es gibt natürlich mehr als einen Weg das zu lösen.

Gruß
BlackMark
 
Ah, das meinst du. Ja, dann schon. Aber ich würde sagen ownership hat der, der den head haltet, und nicht die node. Wer auch immer den head pointer hat, muss auch alle next pointer freigeben.

Gruß
BlackMark
 
ExperienZ schrieb:
Ich soll für die Uni derzeit die String-Klasse "nachahmen". Dabei soll ich sowohl eine Klasse "String2", als auch eine Klasse "CharListenKnoten" schreiben, wobei in einem String-Objekt nur ein Pointer auf den ersten CharListenKnoten dieses Strings sein soll und in den CharListenKnoten-Objekten sind die einzelnen Buchstaben, als Einfach-verkettete Liste eingespeichert.
@kuddlmuddl Die Anforderung der Aufgabe verlangt einen String als linked list zu implementieren. Somit ist std::vector<char> nicht erlaubt und, dass std::string nicht contiguous ist, spielt auch keine Rolle.

Gruß
BlackMark
 
Zurück
Oben