string array dynamisch anlegen



  • Hallo!
    Ich wollte in meiner Klasse ein std::string array dynamisch anlegen, da erst
    zur Laufzeit die Anzahl der Felder bekannt wird.

    class cConfigFile
    {
    	public:
    	cConfigFile(unsigned _NumberOfValues):NumberOfValues(_NumberOfValues) {}
    	~cConfigFile() {};
    
    	private:
    	cConfigFile()
    	{
    	}
    	unsigned NumberOfValues;
    	friend class cConfigEntry;
    };
    
    class cConfigEntry
    {
    	public:
    		~cConfigEntry()
    	{
    		delete[] Value;
    	}
    
    	private:
    	cConfigEntry()
    	{
    		std::string* Value=new std::string[NumberOfValues];
    	}
    	unsigned NumberOfValues;
    	std::string* Value;
        friend class cConfigFile;
    };
    

    Der Konstruktor ist privat, weil nur eine bestimmte Friend-Klasse
    (cConfigFile) ein Objekt dieser Klasse anlegen darf.
    NumberOfValues ergibt sich zur Laufzeit, und ist auch ein Member der
    befreundeten Klasse, deren Deklaration im selben Headerfile ist.
    Ein Objekt der Klasse cConfigFile wird vor cConfigEntry angelegt.
    NumberOfValues ist also bereits vorher bekannt.
    Der Compiler warnt, dass die Variable Value unbenutzt sei.
    Desweiteren ergibt das delete[] Value; einen Segfault.
    Was mach ich falsch?



  • Du definierst einmal einen Pointer auf einen String im privaten Bereich, dann definierst du nochmal einen Pointer mit dem gleichen Namen im Konstruktor, bei dem du dann mit new Speicher allokierst.

    Entferne die Definition std::string in deinem Konstruktor, da der Zeiger ja in der Klasse schon existiert.

    Falls das nich geht schreibe std::string Values; ueber den Konstruktor.

    LG



  • mase schrieb:

    Ich wollte in meiner Klasse ein std::string array dynamisch anlegen, da erst
    zur Laufzeit die Anzahl der Felder bekannt wird.

    Am einfachsten erreichst Du das, wenn Du einfach einen std::vector<> benutzt. Also so

    class cConfigEntry
    {
    public:
    
    private:
        explicit cConfigEntry( unsigned NumberOfValues )
            : m_values( NumberOfValues )
        {}
        // -- Members
        std::vector< std::string > m_values;
        friend class cConfigFile;
    };
    

    das ist dynamisch, Du kannst die Größe des vectors auch noch nachträglich ändern und musst Dich nicht mit dem new & delete rumschlagen.

    Es wird dann noch ein #include <vector> benötigt.

    Gruß
    Werner



  • Ich habe die Vector-Syntax hier nicht so ganz verstanden.
    NumberOfValues soll bei mir die Anzahl der Elemente sein.
    Im privaten Abschnitt hab ich den Vector so deklariert:

    std::vector<std::string>Value;
    

    Dann so implementiert:

    cConfigEntry::vector<string>(NumberOfValues);
    

    In der Klasse hab ich 2 Zugriffsmethoden:

    void cConfigEntry::setValue(string _Value,unsigned _Pos)
    {
    	Value[_Pos]=_Value;
    	return;
    }
    
    string cConfigEntry::getValue(unsigned _Pos)
    {
    	return Value[_Pos];
    }
    

    Doch all das funktioniert nicht.
    Der Compiler meldet bei der Implementierung des Vectors:
    expected constructor, destructor, or type conversion before '<' token
    In der Implementierungsdatei hab ich string und vector auf den std::
    namespace gesetzt.

    Ich hab noch nie vorher einen Vector benutzt. Was mach ich denn jetzt falsch?



  • Jetzt hab ich die Implementierung komplett in der Header-Datei.

    std::vector<std::string>Value(unsigned NumberOfValues);
    

    Jedoch krieg ich bei meinen Zugriffsmethoden:
    invalid types '<unresolved overloaded function type>[unsigned int]' for array subscript



  • mase schrieb:

    Ich habe die Vector-Syntax hier nicht so ganz verstanden.
    NumberOfValues soll bei mir die Anzahl der Elemente sein.
    Im privaten Abschnitt hab ich den Vector so deklariert:

    std::vector<std::string>Value;
    

    das ist korrekt

    mase schrieb:

    Dann so implementiert:

    cConfigEntry::vector<string>(NumberOfValues);
    

    das macht keinen Sinn, lass es einfach weg.

    Es ist im Grunde ganz einfach. Nimm die Klasse cConfigEntry so wie in meinem letzten Posting beschrieben. Füge Deine Zugriffsmethoden hinzu und dann brauchst Du sie nur zu benutzten - also etwa in der Art

    cConfigEntry ce( 10 );
        ce.setValue( "Hallo", 7 );
    

    Erzeugen kannst Du ein Objekt vom Typ cConfigEntry natürlich nur innerhalb von Methoden der Klasse cConfigFile, da der Konstruktor private ist und Du diese als friend deklariert hast.

    Gruß
    Werner



  • Aber wenn ich (NumberOfValues) weglasse, dann ist doch die Anzahl der
    Felder im Vector nicht festgelegt.
    Muss ich ihn dann nicht zwangsläufig mit at() füllen?



  • Den füllst du mit push_back. Er wird dann autom. größer. Die aktuelle Größe kannst du mit size feststellen.

    Mit at() oder []-Operator greifst du zu, auf bereits vorhandene Elemente.

    Schau mal hier:
    http://www.kharchi.de/cppratgeber2.htm



  • Eigentlich wollte ich willkürlich auf die Elemente zugreifen, um sie
    später auch untereinander tauschen zu können.



  • mase schrieb:

    Aber wenn ich (NumberOfValues) weglasse, dann ist doch die Anzahl der
    Felder im Vector nicht festgelegt.

    Wo - meinst Du denn - ist das "NumberOfValues" weggelassen worden?

    mase schrieb:

    Muss ich ihn dann nicht zwangsläufig mit at() füllen?

    "at" ist die Methode die Dir genau wie "[]" den Zugriff auf das i'te Element im vector gibt. Mit dem Unterschied, dass at eine Exception wirft, falls der Index größer oder gleich der Anzahl der Elemente im vector ist.



  • Bei

    cConfigEntry::vector<string>Value(NumberOfValues);
    

    also jetzt

    cConfigEntry::vector<string>Value;
    

    Ersteres verursacht einen Fehler.



  • Nein, das kannst du doch so lassen!

    Werner ging es um das:

    cConfigEntry::vector<string>(NumberOfValues);
    

    Erkennste nicht den Unterschied??? 😕

    Achja, warum machst du eigentlich kein Leerzeichen zwischen Typ und Variable??? Ich meine nur, lässt sich doch dann besser lesen.



  • Jetzt steh ich auf'm Schlauch.
    Ich hab den Vector doch jetzt im Header implementiert.
    Und mit

    cConfigEntry::vector<string>(NumberOfValues);
    

    hätte der Vector doch keinen Namen.
    Der Vector soll Value heissen und NumberOfValues Elemente haben.



  • Eeeeeeben! Deshalb hat Werner gesagt, das es Unsinn ist und weggelassen werden kann!



  • Ich will ihn ja nicht mit push_back füllen, sondern das Element
    explizit angeben.
    In allen Büchern, die ich hab steht:
    vector<typ> name (anzahl der elemente);
    und die Zugriffe mit
    name[element]=wert;
    cout<<name[element];
    Was mach ich denn dann falsch?



  • Jetzt machst du nichts falsch! Lies doch noch mal die Beiträge um was es genau ging.

    So, jetzt ist aber genug...



  • Noch einen Fehler hab ich.

    class cConfigEntry
    {
    	public:
    	~cConfigEntry()
    	{
    	}
    	private:
    	cConfigEntry()
    	{
    		NumberOfValues=1;
    	}
    	cConfigEntry(unsigned _NumberOfValues):NumberOfValues(_NumberOfValues)
    	{
    	}
    	unsigned NumberOfValues;
    	std::vector<std::string>Value(NumberOfValues);
    ...
    };
    

    ergibt, dass NumberOfValues kein Typ sei.

    Dann hab ich einfach mal

    class cConfigEntry
    {
    	public:
    	~cConfigEntry()
    	{
    	}
    	private:
    	cConfigEntry()
    	{
    		NumberOfValues=1;
    	}
    	cConfigEntry(unsigned _NumberOfValues):NumberOfValues(_NumberOfValues)
    	{
    	}
    	unsigned NumberOfValues;
    	std::vector<std::string>Value(unsigned NumberOfValues);
    ...
    };
    

    probiert. Dann krieg ich nur
    invalid types '<unresolved overloaded function type>[unsigned int]' for array subscript
    bei meinen Zugriffsmethoden.



  • mase schrieb:

    Noch einen Fehler hab ich.

    class cConfigEntry
    {
    	public:
    	~cConfigEntry()
    	{
    	}
    	private:
    	cConfigEntry()
    	{
    		NumberOfValues=1;
    	}
    	cConfigEntry(unsigned _NumberOfValues):NumberOfValues(_NumberOfValues)
    	{
    	}
    	unsigned NumberOfValues;
    	std::vector<std::string>Value(NumberOfValues);
    ...
    };
    

    ergibt, dass NumberOfValues kein Typ sei.

    Richtig, weil die Syntax falsch ist. Lies doch bitte die bisherigen Postings durch. dort findest Du:

    Werner Salomon schrieb:

    class cConfigEntry
    {
    public:
    
    private:
        explicit cConfigEntry( unsigned NumberOfValues )
            : m_values( NumberOfValues )
        {}
        // -- Members
        std::vector< std::string > m_values;
        friend class cConfigFile;
    };
    

    In Zeile 10 ist 'm_values' als ein Member der Klasse cConfigEntry deklariert - nicht mehr und nicht weniger. Und erst im Konstruktor von cConfigEntry (in Zeile 7) wird das Objekt 'm_values' der Klasse std::vector< std::string > angelegt und in diesem Fall mit der Anzahl der Elemente initialisiert.

    Gruß
    Werner



  • Ihr werdet es nicht glauben!
    Jetzt hab ich's geschnallt, und es funktioniert jetzt auch bei mir!
    Danke für eure Geduld!


Log in to reply