Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Anonymous

unregistriert

1

02.03.2004, 21:47

Reservierten Speicher vergrössern

Hallo C++ Gemeinde,

ich bin gerade dabei, eine Klasse zur Verwaltung von Strings zu schreiben (ich weiss, es gibt solche Klassen schon. Ich möchte das Rad auch nicht neu erfinden, sondern eher meine c++ Kenntnisse anhand Übung erweitern).

Nun habe ich folgendes Problem. Eine Methode zum setzen des Strings soll den internen Speicherbereich, welchen ich mit new reserivert habe, natürlich vergrössern, sollte der zuvor reservierte Speicherbereich nicht ausreichen.
Beispiel: meine Klasse enthält den String "Hello". Nun will ich den String neu setzen (MyString.setString(char* pStr)) z.B. auf "Hello World" - genau hier muss ich ja den Speicherbereich meines internen Strings vergrössern.

Lange Rede, kurzer Sinn: wie vergrössere ich den Speicherbereich?

Ich hatte schon daran gedacht, den alten String (char*) einfach mit delete zu löschen und ein komplett neuen anzulegen, aber das will leider nicht so ganz funktionieren (ist wahrscheinlich auch sehr unsaubere programmierung).


Vielen Dank für Eure Hilfe!

Beste Grüsse,
Timo

2

02.03.2004, 22:44

Also das mit einfach löschen klingt für meine Ohren nicht schlecht... Wüsste nicht wies sonst gehen soll.

Willst du Speicher hintendrankleben? Woher sollte man wissen dass "hintendran" überhaupt noch Platz ist? Und selbst wenn man`s wissen könnte, würde mir immer noch nichts einfallen, wie man dieses Wissen ausnutzen kann.

Mag ja sein dass ich mich irre, aber ich denke du wirst um löschen und neu anlegen nicht drumherumkommen, zumindest wenn die neue Zeichenkette länger ist als die alte.

Klaus

Treue Seele

Beiträge: 245

Wohnort: Stuttgart

Beruf: Schüler

  • Private Nachricht senden

3

02.03.2004, 23:00

Waren die MFC Quelltexte nicht irgendwie einsehbar? Ich mein, ich hätt das mal gelesen. Müsst nur noch wissen, wo ich die finden kann xD. Bei der CString Klasse kann man sicher sehr schön was abschauen. Oder die Implementierungen Standardheader sind doch auch open source, nöe?
Also von wegen vector<class T>::push_back(...) <-- oder so ähnlich :-D

Irgendwie kann ichs mir nich vorstellen, dass das nich möglich sein soll, weiteren speicher zu erhalten.

Ich informier mich mal - vielleicht find ich ja was :)

bye
Klaus


EDIT/PS:

Also, ich hab da was:
Im Visual C++ (6.0) Verzeichnis findet ihr die Deklaration von class CString in ./VC98/MFC/Include/AFX.H
Die Implementierung hab ich nach langem suchen ( ;D ) in ./VC98/MFC/SRC/STRCORE.CPP gefunden.

Die Speicherreservierung und Freigabe sieht da so aus:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
void CString::AllocBuffer(int nLen)
// always allocate one extra character for '\0' termination
// assumes [optimistically] that data length will equal allocation length
{
    ASSERT(nLen >= 0);
    ASSERT(nLen <= INT_MAX-1);    // max size (enough room for 1 extra)

    if (nLen == 0)
        Init();
    else
    {
        CStringData* pData;
#ifndef _DEBUG
        if (nLen <= 64)
        {
            pData = (CStringData*)_afxAlloc64.Alloc();
            pData->nAllocLength = 64;
        }
        else if (nLen <= 128)
        {
            pData = (CStringData*)_afxAlloc128.Alloc();
            pData->nAllocLength = 128;
        }
        else if (nLen <= 256)
        {
            pData = (CStringData*)_afxAlloc256.Alloc();
            pData->nAllocLength = 256;
        }
        else if (nLen <= 512)
        {
            pData = (CStringData*)_afxAlloc512.Alloc();
            pData->nAllocLength = 512;
        }
        else
#endif
        {
            pData = (CStringData*)
                new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
            pData->nAllocLength = nLen;
        }
        pData->nRefs = 1;
        pData->data()[nLen] = '\0';
        pData->nDataLength = nLen;
        m_pchData = pData->data();
    }
}

void FASTCALL CString::FreeData(CStringData* pData)
{
#ifndef _DEBUG
    int nLen = pData->nAllocLength;
    if (nLen == 64)
        _afxAlloc64.Free(pData);
    else if (nLen == 128)
        _afxAlloc128.Free(pData);
    else if (nLen == 256)
        _afxAlloc256.Free(pData);
    else  if (nLen == 512)
        _afxAlloc512.Free(pData);
    else
    {
        ASSERT(nLen > 512);
        delete[] (BYTE*)pData;
    }
#else
    delete[] (BYTE*)pData;
#endif
}


Nach der _afxAlloc[N].Alloc() dürft ihr selber schauen ;)
Ich hab keine Zeit mehr - schreib morgen Englisch :ohoh: :rolleyes:

n8
Mozilla Firefox
The Browser - reloaded

Anonymous

unregistriert

4

03.03.2004, 00:44

Hallo,

danke für die Antworten. Irgendwie kann ich mit dem großen Quelltext nichts anfangen, dafür habe ich wohl noch zu wenig C++ Erfahrung. Allerdings glaube ich auch, dass dort meine Frage nicht beantwortet wird, ich müsste mir wahrscheinlich diese alloc Funktionen genauer anschauen...

Naja ich werde mal weiter nachforschen und lernern :-)

Falls jemand noch Tipps/Infos hat, wäre ich sehr dankbar.


Beste Grüsse,
Timo

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

5

03.03.2004, 10:03

Neuen Bereich mit new anlegen, Inhalt des alten in den neuen kopieren, alten freigeben.

Klaus

Treue Seele

Beiträge: 245

Wohnort: Stuttgart

Beruf: Schüler

  • Private Nachricht senden

6

03.03.2004, 14:43

Zitat von »"Osram"«

Neuen Bereich mit new anlegen, Inhalt des alten in den neuen kopieren, alten freigeben.


Gehts also tatsächlich nicht anders?
Mozilla Firefox
The Browser - reloaded

Anonymous

unregistriert

7

03.03.2004, 15:25

Na dann hatte ich ja doch die richtige Idee, das ganze klang mir nur irgendwie zu "plump" ;-)

Nunja, wenn Ihr mögt könnt Ihr ja mal kurz einen Blick auf diese Klasse werfen, erst die Header Datei:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef _CSTR_H
#define _CSTR_H


class CStr
{
private:
    char* pStringData;

public:
    CStr();                     // Default Konstruktor
    CStr(const char*);          // Konstruktor mit Parameter Pointer auf String
    ~CStr();                    // Dekonstruktor

    char* getString();              // Liefert einen Zeiger auf den aktuellen String zurück
    void setString(const char*);    // Setzt den Inhalt der String Klasse
};

#endif



Und hier die Implementation:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "../include/CStr.h"
#include <windows.h>

CStr::CStr()
{
    pStringData = new char[0];
}

CStr::CStr(const char* pStr)
{
    pStringData = new char[ sizeof(*pStr) ];
    strcpy(pStringData, pStr);
}

CStr::~CStr()
{
    delete pStringData;
}

char* CStr::getString()
{
    return pStringData;
}

void CStr::setString(const char* pStr)
{
    // Speicher neu reservieren
    delete this->pStringData;
    this->pStringData = new char[ sizeof(*pStr) ];

    strcpy(this->pStringData, pStr);

    //MessageBox(0, pStr, "test", MB_ICONINFORMATION);

}


Wie man sieht, wird bei CStr::setString der Speicherbereich neu angelegt. Dies funktioniert auch - jedoch nur einmal! Der zweite Aufruf von CStr::setString produziert einen Fehler, ebenso wie das zerstören des Objektes der CStr Klasse. Der Fehler, so wie ich stark vermute, liegt beim "delete this->pStringData;" bzw. bei der delete - Zeile des Dekonstruktors.

Mache ich also folgendes:

Quellcode

1
2
3
CStr* pMeinString = new CStr();
pMeinString->setString("Hallo");
delete pMeinString;


So kommt ein merkwürdiger Fehler, der lautet:

---------------
Debug Error!
Program: ..../test.exe
DAMAGE: after Normal block (#46) at 0x00AB07D0
---------------


Nehme ich die delete Zeile im Dekonstruktor raus, so funktioniert alles.

Kann mir jemand erklären, woran das liegt?


Danke!


Beste Grüsse,
Timo

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

8

03.03.2004, 16:21

Zitat


Gehts also tatsächlich nicht anders?


Es geht auch anders, aber das hier ist die beste Methode.

<Nur weiterlesen, wenn Ihr verwirrt werden wollt>
Eine weitere Möglichkeit ist realloc.
</Nur weiterlesen, wenn Ihr verwirrt werden wollt>


Quellcode

1
2
3
4
5
CStr::CStr(const char* pStr)
{
   pStringData = new char[ sizeof(*pStr) ];
   strcpy(pStringData, pStr);
}


wird zu

Quellcode

1
2
3
4
5
CStr::CStr(const char* pStr)
{
   pStringData = new char[ strlen(*pStr) +1]; // +1 for the trailing \0
   strcpy(pStringData, pStr);
}


Aus allen "delete" machst Du ein "delete []". In SetString auch das "strlen()+1" nicht vergessen, um die Länge des Strings inkl dem Abschluß 0 Byte zu erhalten.

Till

Alter Hase

Beiträge: 378

Wohnort: Lincoln College, Oxford

Beruf: Student

  • Private Nachricht senden

9

03.03.2004, 16:22

Also,

ich bin auch nicht grade der C++-PROFI, aber ich würde das alles ein wenig anders machen:

...new char[sizeof(*pStr)];

So wie ich das sehe, reservierst du doch nur Speicher für ein EIN-BYTE-CHAR-ARRAY, da die Größe der Dereferenz von pStr doch nur ein Byte beträgt, oder?
Wäre

..new char[strlen(pStr)];

nicht besser, was dann auch durch

..delete[] pStr;

gelöscht wird?

Und zur Speichervergrößerung:

void *realloc( void *memblock, size_t size );

in <stdlib.h> und <malloc.h>
DOMINVS ILLVMINATIO MEA
---
Es lebe unmanaged Code!
---
>> Meine Uni <<

Anonymous

unregistriert

10

03.03.2004, 19:35

Hallo Till,

Zitat


So wie ich das sehe, reservierst du doch nur Speicher für ein EIN-BYTE-CHAR-ARRAY, da die Größe der Dereferenz von pStr doch nur ein Byte beträgt, oder?


oh hmm... ich dachte bisher, die Dereferenz von pStr sei der String darin, sodass sizeof() dann die Größe dieses Strings wieder gibt? Vielleicht habe ich mich natürlich auch geirrt, ich schau mir das später mal im detail an.

Zitat


nicht besser, was dann auch durch

..delete[] pStr;

gelöscht wird?


wieso sollte denn pStr gelöscht werden? Der interne String ist ja pStringData, und genau da ist ja auch das Problem, diesen zu löschen. Und ich weiss einfach nicht, warum dieser Fehler da kommt... :ohoh:

Werbeanzeige