nullpointer in Funktion auf neu erzeugtes Objekt





  • @Swordfish so habe ich es auch verstanden. Leider bin ich noch zu unerfahren, um jetzt festzustellen, woran genau es bei mir scheitert. Ich erzeuge in der createSubVectorOnhead() aus dem übergebenen source (walter) mit walter.getSubVector(begin, end) einen Vektor und versuche dem übergebenen Pointer die Adresse von diesem neuen Vektor zuzuweisen. Wenn ich nun allerding *ptr->print() aufrufe, bekomme ich für die einzelnen Werte nur Murks (irgendein hoher negativer Wert).


  • Mod

    @Swordfish sagte in nullpointer in Funktion auf neu erzeugtes Objekt:

    @SeppJ sagte in nullpointer in Funktion auf neu erzeugtes Objekt:

    das ist ein Fehler in der Aufgabe.

    Fehler würde ich es nicht nennen.

    IVektor *walter{ nullptr };
    createSubVectorOnHeap(hugo, &walter, 0, 42);
    

    Kann man machen, klar. Ist aber für die Funktion vollkommen wurscht und verwirrt nur den Schreiber der Funktion, der sich fragt, wozu diese komische Anforderung da ist.



  • Das hier ist meine IVektor.cpp

    #include "IVektor.h"
    #include <iostream>
    
    
    //######### Konstruktoren / Destruktor ########
    IVektor::IVektor(int n) 
    {
    	daten = new int[n];
    	size = n;
    	if (daten != nullptr) {
    		for (int i = 0; i < size; i++) {
    			daten[i] = 0;
    		}	
    	}
    }
    
    IVektor::IVektor() 
    {
    	daten = new int[1];
    	size = 1;
    	daten[0] = 0;
    }
    
    IVektor::IVektor(const IVektor& v)
    {
    	size = v.size;
    	daten = new int[size];
    
    	for (int i = 0; i < size; i++)
    		daten[i] = v.daten[i];
    }
    
    IVektor::~IVektor()
    {
    	delete[] daten;
    }
    
    //######### Methoden ########
    int IVektor::getSize()
    {
    	return size;
    }
    
    int IVektor::getAt(int n)
    {
    	if (n < 0)
    		n = 0;
    	if (n >= size)
    		n = size - 1;
    	return daten[n];
    }
    
    void IVektor::setAt(int n, int value) {
    	if (n < 0)
    		n = 0;
    	if (n >= size)
    		n = size - 1;
    	daten[n] = value;
    }
    
    IVektor IVektor::getSubVektor(int begin, int end)
    {
    	if (begin < 0)
    		begin = 0;
    	if (end >= size)
    		end = size - 1;
    	IVektor temp(end - begin + 1);
    	for (int i = 0; begin <= end; begin++)
    	{
    		temp.daten[i] = daten[begin];
    		i++;
    	}
    	return IVektor(temp);
    }
    
    void IVektor::setSubVektor(IVektor v)
    {
    	for (int i = 0; (i < size) && (i < v.getSize()); i++)
    		daten[i] = v.daten[i];
    }
    
    void IVektor::print() const
    {
    	std::cout << "{";
    	for (int i = 0; i < size; i++) {
    		std::cout << daten[i];
    		if (i < size - 1) {
    			std::cout << " | ";
    		}
    	}
    	std::cout << "}";
    	std::cout << std::endl;
    }
    
    IVektor IVektor::getSubVektor(int begin, int end) const
    {
    	if (begin < 0)
    		begin = 0;
    	if (end >= size)
    		end = size - 1;
    	IVektor temp(end - begin + 1);
    	for (int i = 0; begin <= end; begin++)
    	{
    		temp.daten[i] = daten[begin];
    		i++;
    	}
    	return IVektor(temp);
    }
    
    void IVektor::print() {
    	std::cout << "{";
    	for (int i = 0; i < size; i++) {
    		std::cout << daten[i];
    		if (i < size - 1) {
    			std::cout << " | ";
    		}
    	}
    	std::cout << "}";
    	std::cout << std::endl;
    }
    
    

  • Mod

    @manni1333 sagte in nullpointer in Funktion auf neu erzeugtes Objekt:

    Ich hab hier mal die gesamte Aufgabe hochgeladen.

    https://www.ilovepdf.com/de/download/qwyt0b0nyw8A4kr4400jAj2rdr5tA7thzy1svxh5rsn7b6sywkn3gdm22k8vxfxg883s56bnvxpkw21x24Acxltrzs0cy531vh4t6rt9hlwkr73tykt1khx8h4611pkp9Ayxv7d41bqhzdkjzjvlb6dx02/14

    Unten Aufgabe 1.5... 😕

    Bestätigt meine Aussage. Die Anforderung mit dem nullptr ist für die Funktion createSubVectorOnHeap vollkommen egal. Und auch für den Aufrufer. Man kann sie natürlich ganz leicht erfüllen (siehe Swordfish), aber lass dich auf keinen Fall davon verwirren. Du kannst so tun, als wäre die Anforderung nicht da. Damit alles klar?

    Wenn man die ganze Aufgabe sieht, bestätigt sich auch meine Aussage, dass es eine eher mäßige Aufgabe ist, aber keine ganz falsche. Die Aufgabe macht zwar auf einige der Probleme in ihren eigenen Anforderungen aufmerksam und lässt Lösungen erarbeiten, aber eben nicht auf alle Probleme. Ich fürchte fast, der Aufgabensteller ist sich nicht unbedingt selbst aller Probleme bewusst.

    Falls du eine vollständige Diskussion der Probleme wünscht (und das solltest du, wenn es dir ernst ist), dann googel mal nach den Stichworten RAII und Rule of 3. Das sind zentrale Konzepte von C++. Wobei man sie am Ende doch so gut wie nie braucht (Stichwort: Rule of 0), aber es ist Pflicht, davon mal gehört zu haben, damit man weiß, was man tut.



  • @SeppJ sagte in [nullpointer in Funktion auf neu erzeugtes Objekt]

    Bestätigt meine Aussage. Die Anforderung mit dem nullptr ist für die Funktion createSubVectorOnHeap vollkommen egal. Und auch für den Aufrufer. Man kann sie natürlich ganz leicht erfüllen (siehe Swordfish), aber lass dich auf keinen Fall davon verwirren. Du kannst so tun, als wäre die Anforderung nicht da. Damit alles klar?

    Nicht so wirklich. Vielleicht habe ich ja auch grobe Fehler in der IVektor.cpp. Das hier ist mein bisheriger Versuch bei der Funtkion:

    void createSubVectorOnHeap(const IVektor& source, IVektor** pSubVec, int begin, int end)
    {
        *pSubVec = &source.getSubVektor(begin, end);
    }
    ...
        IVektor* ptr = nullptr;
        IVektor v(10);
        createSubVectorOnHeap(v, &ptr, 2, 5);
        ptr->print();
    ..
    

    Die Ausgabe der print-Funktion ist einfach nur "{}"



  • Schaut allgemein ein bisschen zu komplifiziert aus was Du da machst.

    #include <iostream>
    #include <algorithm>
    
    class IVector
    {
    	int size;
    	int *data;
    
    	int sanitizePosition(int n) const
    	{
    		if (n < 0)
    			return 0;
    		if (n + 1 > size)
    			return size - 1;
    		return n;
    	}
    
    public:
    	IVector(int n = 0)
    	: size{ n ? n : 1 },
    	  data{ new int[size]{} }
    	{}
    
    	IVector(IVector const& other)
    	: size{ other.size },
    	  data{ new int[size] }
    	{
    		std::copy(other.data, other.data + size, data);
    	}
    
    	~IVector() { delete[] data; }
    
    	int getSize() const { return size; }
    
    	int getAt(int n) const
    	{
    		n = sanitizePosition(n);  // eigentlich std::clamp()
    		return data[n];
    	}
    
    	void setAt(int n, int value)
    	{
    		n = sanitizePosition(n);  // eigentlich std::clamp()
    		data[n] = value;
    	}
    
    	IVector getSubVector(int begin, int end) const
    	{
    		begin = sanitizePosition(begin);
    		end = sanitizePosition(end);
    		IVector result{ end - begin + 1 };
    		std::copy(data + begin, data + end + 1, result.data);
    		return result;
    	}
    
    	void setSubVector(IVector const& v)
    	{
    		int max_size{ std::min(size, v.size) };
    		std::copy(v.data, v.data + max_size, data);
    	}
    
    	void print() const
    	{
    		std::cout << std::hex << this << std::dec << ": ";
    		for (int i{}; i < size; ++i)
    			std::cout << data[i] << ' ';
    		std::cout.put('\n');
    	}
    };
    
    void test1(int chunkSize)
    {
    	IVector v(chunkSize);
    	std::cout << v.getSize() << '\n';
    }
    
    void test2()
    {
    	IVector v1{ 10 };
    	IVector v2{ 10 };
    	
    	for (int i = 0; i < 10; ++i)
    		v1.setAt(i, i + 1);
    
    	v1.print();
    	v2.print();
    	v2.setSubVector(v1);
    	v1.print();
    	v2.print();
    }
    
    void test3()
    {
    	IVector v1{ 10 };
    	IVector v2 = v1;
    
    	for (int i = 0; i < 10; ++i)
    		v1.setAt(i, i + 1);
    
    	v1.print();
    	v2.print();
    
    	for (int i = 0; i < 10; ++i)
    		v2.setAt(i, 10 - i);
    
    	v1.print();
    	v2.print();
    }
    
    void createSubVectorOnHeap(IVector const &source, IVector **pSubVec, int begin, int end)
    {
    	*pSubVec = new IVector{ source.getSubVector(begin, end) };
    }
    
    int main()
    {
    	std::cout << "test1:\n";
    	constexpr int iter{ 1000 };
    	constexpr int chunkSize{ 1000000 };
    	for (int i = 0; i < iter; ++i)
    		test1(chunkSize);
    
    	std::cout << "\ntest2:\n";
    	test2();
    
    	std::cout << "\ntest3:\n";
    	test3();
    
    	std::cout << "\nAufgabe 1.5:\n";
    	IVector xaver(10);
    	for (int i{}; i < xaver.getSize(); ++i)
    		xaver.setAt(i, i * 2);
    	xaver.print();
    
    	IVector *franz{ nullptr };
    	createSubVectorOnHeap(xaver, &franz, 4, 7);
    	franz->print();
    	delete franz;
    }
    


  • @manni1333 sagte in nullpointer in Funktion auf neu erzeugtes Objekt:

    *pSubVec = &source.getSubVektor(begin, end);
    

    Ähm, ne, Du kannst nicht einfach die Adresse von dem von getSubVektor() zurückgegebenen temporary nehmen. Das lebt nur bis zum Ende des Statements in dem getSubVektor() aufgerufen wird. Du musst schon new bemühen und eine Kopie machen.



  • @Swordfish Wow vielen Dank!! 😃



  • @Swordfish Dann fehlt es mir wohl noch am grundsätzlichen Verständnis. Ist das in der Funktion mit new erzeugte Objekt nicht auch nur temporär bis zum Ende der Funktion?



  • @manni1333 sagte in nullpointer in Funktion auf neu erzeugtes Objekt:

    Ist das in der Funktion mit new erzeugte Objekt nicht auch nur temporär bis zum Ende der Funktion?

    Was von new (new[]) kommt lebt bis es mit delete (delete[]) weggeräumt wird.



  • @Swordfish Oh man, das werde ich nie wieder vergessen. Danke für deine Hilfe 🙂


Log in to reply