Run-Time Check Failure #2



  • Hallo alle zusammen,
    also ich komme bei meinem Code irgendwie nicht weiter. Die Aufgabenstellung war, eine Klasse zu implementieren mit der man dann mit Vektoren arbeiten kann.
    Grundsätzlich ist es uns erlaubt die Klasse vector<double> zu benutzen, aber ich wollte es gerne einmal ohne versuchen.
    Im Prinzip bekomme ich auch alle Ausgaben, so wie ich sie wollte, bis auf ein kleines Problem wenn ich das Programm wieder schließen möchte.
    Wenn ich dann eine beliebige Taste zum schließen der Console drücke, bekomme ich den Fehler "Run-Time Check Failure #2 - Stack around the variable 'v' was corrupted."

    Meine Headerdatei sieht bis jetzt so aus:

    #pragma once
    class CMyVektor
    {
    private:
    	int dimension;
    	double vektor[];
    public:
    	int createV(int dim);
    	int getDimension();
    	double setComp(int comp, double compWert);
    	double getComp(int comp);
    	double getLength();
    	int getVektor();
    };
    
    

    Meine .cpp mit den ganzen Funktionen sieht so aus:

    #include "CMyVektor.h"
    #include <iostream>
    #include "math.h"
    
    using namespace std;
    
    int CMyVektor::createV(int dim)
    {
    	dimension = dim;
    	vektor[dimension];
    	for (int i = 0; i < dim; i++)
    	{
    		vektor[i] = 0;
    	}
    
    	return 0;
    }
    
    int CMyVektor::getDimension()
    {
    	cout << "Die Dimension des Vektors betraegt: " << dimension << endl;
    	return dimension;
    }
    
    double CMyVektor::setComp(int comp, double compWert)
    {
    	if (comp > 0 && comp <= dimension)
    	{
    		vektor[comp-1] = compWert;
    	}
    	else
    	{
    		cout << "Komponente nicht vorhanden. Richtige Dimension??" << endl;
    	}
    	return 0;
    }
    
    double CMyVektor::getComp(int comp)
    {
    	cout << "Die Komponente x" << comp << " des Vektors betraegt: " << vektor[comp-1] << endl;
    	return vektor[comp-1];
    }
    
    double CMyVektor::getLength()
    {
    	double a = 0;
    	for (int i = 0; i < dimension; i++)
    	{
    		a += pow(vektor[i], 2);
    	}
    	double length = sqrt(a);
    	cout << "Die Laenge des Vektors betraegt: " << length << endl;
    	return length;
    }
    
    int CMyVektor::getVektor()
    {
    	int i = 0;
    	for (int i = 0; i < dimension; i++)
    	{
    		cout << "| " << vektor[i] << " |" << endl;
    	}
    	return dimension;
    }
    
    

    Kann mir einer vielleicht erklären wodurch der Fehler verursacht wird?



  • @Daniel-l06

    vektor[dimension]; macht nicht, was du glaubst. Benutze std::vector!



  • @manni66 Erstmal danke für deine Antwort! Kannst du mir eventuell trotzdem erklären wodurch der Fehler genau entsteht? Dass vektor[dimension] wohl nicht das macht was ich denke, ist ja ein Indiz dafür, dass ich etwas nicht ganz verstanden habe. Ich würde es aber echt gerne verstehen^^'



  • Was soll vektor[dimension] denn anderes machen als auf das (nicht-existente) Element mit dem Index dimension zuzugreifen und das Ergebnis sogleich wieder zu verwerfen? Kann es sein, dass du vorher in einer Sprache programmiert hast, in der man Arrays vergrößern kann, indem man auf nichtexistente Elemete zugreift? (Ich glaube Matlab macht das so)
    In C++ ist das jedenfalls nicht so. Das im Einzelnen zu erklären führt hier zu weit. Lerne das mithilfe der üblichen Medien, z.B. mit einem Buch, und frage bei Unklarheiten nach.



  • Nein, ich werde das nicht erklären. Du hast einen Lehrer, std::vector ausdrücklich erlaubt. Herzlichen Glückwunsch. Du lernst C++, nicht C mit Klassen.



  • @Bashar Hey, ich habe davor noch nie in einer Sprache programmiert. Ich habe jetzt erst in meinem ersten Semster mit C++ angefangen. Dein Kommentar konnte mir aber einen, ich denke guten, Denkanstoß geben! Ich habe das jetzt so verändert, dass ich statt dem Array in der Headerdatei einen double* Vektor initialisiere und dann in der .cpp mit dem new Operator dem Array die geforderte Größe zuweise.



  • @Daniel-l06 sagte in Run-Time Check Failure #2:

    einen double* Vektor initialisiere und dann in der .cpp mit dem new Operator dem Array die geforderte Größe zuweise.

    Das klingt nicht nur spooky sondern sieht vermutlich noch spookiger aus.



  • @Swordfish Echt? ^^' Also es sieht halt jetzt so aus. Im prinzip müsste ich doch jetzt nur noch eine Funktion einbauen, die den Speicher wieder freigibt und diese immer kurz vor Ende des Programms ausführen, oder?

    #pragma once
    class CMyVektor
    {
    private:
    	int dimension;
    	double* vektor;
    public:
    	int createV(int dim);
    	int getDimension();
    	double setComp(int comp, double compWert);
    	double getComp(int comp);
    	double getLength();
    	int getVektor();
    };
    
    int CMyVektor::createV(int dim)
    {
    	dimension = dim;
    	vektor = new double[dimension];
    
    	return 0;
    }
    


  • @Daniel-l06

    oder?

    Nein.



  • @manni66 Hey, ich habe deinen Standpunkt verstanden. Ich soll die std::vector benutzen. Schön. Wenn du mir aber sonst nicht weiter helfen möchtest, dann lass es doch einfach? Ich möchte es halt ohne versuchen. Wenn ich ohne absolut nicht mehr weiter komme greife ich darauf zurück, mein gott. Lass mich doch probieren und gucken was geht und was nicht.





  • @Swordfish Danke dir, ich werde es mir durchlesen! 🙂



  • @Daniel-l06 sagte in Run-Time Check Failure #2:

    Hey, ich habe deinen Standpunkt verstanden. Ich soll die std::vector benutzen.

    Ja! Und sei froh, dass dein Lehrer / Dozent das erlaubt! Wirklich! Es schlagen hier so viele Leute auf, die auf die eine oder andere Art 1000 Probleme haben, nur weil sie auf gar keinen Fall std::vector benutzen dürfen. (Phänomen "inkompetenter Lehrer")

    Korrekte Ressourcenverwaltung ist nicht leicht, wenn du alles richtig machen willst. Unter anderem musst du dich mit der Frage beschäftigen, was bei Exceptions passiert. Bei einem double als Typ treten die zwar nicht auf (außer jetzt dass das new fehlschlagen könnte), aber bei andere Typen ggf. schon. Siehe auch mal: https://en.wikipedia.org/wiki/Exception_safety
    Wenn du das erstmal außer acht lässt und dann die rule of 3 (oder 5) befolgst, funktioniert dein Code zumindest schonmal. Aber wie gesagt, einfacher wäre, einfach std::vector zu nehmen. Seltsamerweise ist die Frage, wir man Arrays in Python oder ArrayLists in Java implementiert, mir noch nicht untergekommen - da wird einfach munter drauf los benutzt. Nur bei C++ scheint es irgendwie (insbesondere von Anfängern) ein Bedürfnis zu geben, die eingebauten Typen selbst neu schreiben zu wollen...



  • @wob ich denke das Bedürfnis kommt daher, dass C++ eine der wenigen Programmiersprachen ist, wo sich Objekte von Klassen tatsächlich auch wie eingebaute Typen anfühlen.

    Aber ehrlich gesagt, finde ich es auch nicht Schlimm, dass ein Anfänger auch in C++ mal mit new und delete rumärgern sollte.

    In Java ist zumindest eine häufige Übungsaufgabe eine verkettete Liste zu bauen und nicht LinkedList zu verwenden.

    Grüße



  • Ich denke, das kommt von der C-Vergangenheit. Es wird oft behauptet, um C++ zu verstehen, muss man C verstehen.
    Auch wenn das irgendwo vollkommen daneben ist, Phyton und Java müssen sich dieser Vergangenheitsfrage nicht stellen.



  • @zeropage weiß nicht.

    #include <cstddef>
    #include <stdexcept>
    #include <string>
    
    template<typename T>
    class vector_t
    {
    public:
    	using value_type       = T;
    	using pointer          = T*;
    	using reference        = T&;
    	using const_reference  = T const&;
    	using size_type        = std::size_t;
    
    private:
    	std::size_t  data_size;
    	std::size_t  data_capa;  // capacity
    	std::byte   *data;
    
    public:
    	vector_t(std::size_t size = 0, value_type const &value = value_type{})
    	: data_size { size },
    	  data_capa { size },
    	  data      { new std::byte[data_capa * sizeof value_type] }
    	{
    		for (size_type i{}; i < data_size; ++i)
    			new (reinterpret_cast<pointer>(data) + i) value_type{ value };
    	}
    
    	vector_t(vector_t<T> const &other)
    	: data_size { other.data_size },
    	  data_capa { other.data_size },
    	  data      { new std::byte[data_capa * sizeof value_type] }
    	{
    		for (size_type i{}; i < data_size; ++i)
    			new (reinterpret_cast<pointer>(data) + i) value_type{ reinterpret_cast<pointer>(other.data)[i] };
    	}
    
    	friend void swap(vector_t<T> &a, vector_t<T> &b) noexcept
    	{
    		using std::swap;
    		swap(a.data_size, b.data_size);
    		swap(a.data_capa, b.data_capa);
    		swap(a.data, b.data);
    	}
    
    	vector_t& operator=(vector_t<T> other) noexcept
    	{
    		swap(*this, other);
    		return *this;
    	}
    
    	virtual ~vector_t()
    	{
    		for (size_type i{}; i < data_size; ++i)
    			reinterpret_cast<pointer>(data)[i].~value_type();
    		delete[] data;
    	}
    
    	std::size_t size() const noexcept { return data_size; }
    	
    	reference operator[](std::size_t index) { return reinterpret_cast<pointer>(data)[index]; }
    	
    	reference at(std::size_t index)
    	{
    		if (data_size <= index)
    			throw std::out_of_range{ "vector_t::at(" + std::to_string(index) + ")" };
    		return reinterpret_cast<pointer>(data)[index];
    	}
    };
    

    schaut nicht aus wie C.



  • @wob sagte in Run-Time Check Failure #2:

    Aber wie gesagt, einfacher wäre, einfach std::vector zu nehmen. Seltsamerweise ist die Frage, wir man Arrays in Python oder ArrayLists in Java implementiert, mir noch nicht untergekommen - da wird einfach munter drauf los benutzt. Nur bei C++ scheint es irgendwie (insbesondere von Anfängern) ein Bedürfnis zu geben, die eingebauten Typen selbst neu schreiben zu wollen...

    (*this)!



  • Ich glaube, das kommt tatsächlich daher, dass das in C oder C++ tatsächlich eine Herausforderung darstellen kann. Gerade wegen der komplizierteren Speicherverwaltung, Exception Safety, Rule of 3/5/0 usw.
    In Java ist es total langweilig, eine LinkedList zu schreiben. Was soll man dabei lernen?


  • Mod

    @Mechanics sagte in Run-Time Check Failure #2:

    Ich glaube, das kommt tatsächlich daher, dass das in C oder C++ tatsächlich eine Herausforderung darstellen kann. Gerade wegen der komplizierteren Speicherverwaltung, Exception Safety, Rule of 3/5/0 usw.
    In Java ist es total langweilig, eine LinkedList zu schreiben. Was soll man dabei lernen?

    Wenn man's strikt idiomatisch macht, ist die LinkedList auch in C++trivial, weil man dann zur Verbindung Smartpointer nimmt, wodurch Speicherverwaltung entfällt und es - wie in Java - letztlich nur darauf ankäme, die Punkte richtig zu verbinden. Aber wenn die Anfänger ihrem Bedürfnis nachgeben, alle Standardcontainer selber zu implementieren, dann machen sie es ja auch gleich noch so wie es K&R anno 1970 gemacht hätten.



  • @SeppJ würdest Du bitte meinen Code oben mal zerreißen?


Anmelden zum Antworten