<vector> ?

Status
Niet open voor verdere reacties.

BART1234567

Nieuwe gebruiker
Lid geworden
8 dec 2008
Berichten
4
Ik probeer al enkele dagen de std::vector aan de praat te krijgen maar krijg constant segmentationfaults bij het verwijderen...

Dit is de sourcecode:
Code:
// Ergens in de code heb ik een vector v1 waaraan ik enkele objecten van type Test aan meegeef. Dit werkt allemaal goed.
// De Test class heeft 2 members m1 en m2 die tezamen een "gewicht" voorstellen (het gewicht = m1 * m2). 
// Nu probeer ik een nieuwe vector aan te maken waarbij het gewicht van de objecten in v1 gesorteerd is volgens oplopende grootte.

vector<Test*> v2;
int size = v1.size();
	for(int i = 0; i < size; i++)
	{
		Test* smallest = v1[0];
		int max = v1.size();
		int loc = 0;
		for(int j = 0; j < max; j++)
		{
			double w1 = smallest->m1 * smallest->m2;
			double w2 = v1[j]->m1 * v1[j]->m2;
			if (dl2 < dl1)
			{
				smallest = v1[j];
				loc = j;
			}
		}
		v2[i] = smallest;
		v1.erase(v1.begin() + loc);
	}
	// v2 bevat nu alle objecten van v1, gesorteerd volgens hun gewicht?

Na toevoeging van enkele cout berichten blijkt het dat de ene keer er onmiddelijk een segmentationfault optreedt, de andere keer pas na verwijderen van, pakweg, 3 objecten in de vector.

Waar zit de fout?
 
Dank je, dat is uiteraard een veel eenvoudigere oplossing, die ik dan ook zal gebruiken, maar waar ligt de fout ergens in mijn huidige code? Kwestie van soortgelijke fouten te vermijden?
 
Dank je, dat is uiteraard een veel eenvoudigere oplossing, die ik dan ook zal gebruiken, maar waar ligt de fout ergens in mijn huidige code? Kwestie van soortgelijke fouten te vermijden?

Waarschijnlijk omdat de grootte van je vector wijzigt.

Code:
int size = v1.size(); // size heeft een vaste lengte
for(int i = 0; i < size; i++) // deze lengte wordt gebruikt om alle elementen te doorlopen
//...
v1.erase(v1.begin() + loc); // verwijder een element uit de vector -> de grootte van de vector wordt inherent hieraan met één verlaagd -> lengte is niet meer gelijk aan de variabele 'size'

(verder hoef je geen tijdelijke variabele te gebruiken, maar zou je ook std::swap kunnen gebruiken)
 
Waarschijnlijk omdat de grootte van je vector wijzigt.
Nee dit is het probleem niet. Inderdaad hij verkleint de vector v1 bij elke iteratiestap van de buitenste lus. Maar neen dit is niet de reden waarom hij een segmentatie fout krijgt. Het is heel makkelijk in te zien waarom met het volgende vb:
PHP:
// Stel v is een vector die in een voorgaande deel geïnitialiseerd is.
for(int i = 0; i < v.size(); ++i) {
     v.erase(0); // dit zal nooit een segfault geven. Wat hier gebeurt is het 1 voor 1 wissen van alle elementen in de vector.
}

En dit is in essentie wat hij doet bij die erase. Met dit verschil dat hij niet telkens op postie 0 gaat wissen maar op positie 0 <= v1.begin() + loc < v1.size(). Waarbij v1.size telkens opnieuw wordt opgevraagd in de inner loop. Bijgevolg kan hij daar nooit buiten de grensen lopen (hij houdt al dan niet gewild rekening met de dynamische grootte van de vector v1 door in de inner lus expliciet v1.size() te gebruiken).

Dit gezegd zijnde, de fout is ongeloofelijk simpel. De volgende statement wordt in begin gedaan.:
PHP:
vector<Test*> v2;

Hierna gaat je gewoon dit doen:
PHP:
v2[i] = smallest;

Wat niet kan, je vraagt aan een vector met size 0 of hij zijn eerste element wil geven. Kan toch niet? v2.push_back(smallest) zou lukken.

Vb code:
PHP:
#include <stdio.h>
#include <stdlib.h>
#include <Vector>

using namespace std;

class Test {
public:
	Test(double m1, double m2) : m_m1(m1), m_m2(m2) {;}
	double getM1(void) const {return m_m1;}
	double getM2(void) const {return m_m2;}
private:
	double m_m1, m_m2;    
};

void sort(vector<Test*> & v2, vector<Test*> & v1);
void initVector(vector<Test*> & v);

int main(void) {
	vector<Test*> v1, v2;

	initVector(v1);
	sort(v2, v1);
}

void initVector(vector<Test*> & v) {
	for(int i = 0; i < 10; ++i) {
	//	v[i] = new Test(rand()%100, rand()%100); mag niet v[i] geeft het n-de element terug. Maar er zijn geen elementen hoe zou hij het dan kunnen teruggeven??
        v.push_back(new Test(rand()%100, rand()%100));
	}
}

void sort(vector<Test*> & v2, vector<Test*> & v1) {
	int size = v1.size();
	Test* smallest;
	double w1, w2;
	v2.resize(size);

	for(int i = 0; i < size; ++i) {
		smallest = v1[0];
		int max = v1.size();
		int loc = 0;

		for(int j = 0; j < max; ++j) {
			w1 = smallest->getM1() * smallest->getM2();
			w2 = v1[j]->getM1() * v1[j]->getM2();

			if (w2 < w1) {
				smallest = v1[j];
				loc = j;
			}
		}
        
        // Dit geeft dezelfde fout als hierboven.
        // Dit is nu opgelost door de size van de vector op voorhand vast te leggen.
		v2[i] = smallest;
		v1.erase(v1.begin() + loc);
	}

}
 
Dit gezegd zijnde, de fout is ongeloofelijk simpel. De volgende statement wordt in begin gedaan.:
PHP:
vector<Test*> v2;

Hierna gaat je gewoon dit doen:
PHP:
v2[i] = smallest;

Wat niet kan, je vraagt aan een vector met size 0 of hij zijn eerste element wil geven. Kan toch niet? v2.push_back(smallest) zou lukken.

Oke, dan zat ik in de verkeerde richting. Bedankt voor het verbeteren. :)
 
Ok, dank je, 't is me veel duidelijker nu.

Toch nog een totaal ongerelateerde vraag (niet zoveel goesting om hier nieuwe thread voor te openen):

Stel ik heb een class gemaakt met o.a. static members:

class MyClass
{
const static int i1 = 5;
static MyOtherClass* m;
}

MyOtherClass* MyClass::m = new MyOtherClass()

const statics kan je initializeren binnen de klassedefinitie, en een gewone static initializeer ik dan in de sourcecode zelf...

Maar als ik nu al enkele methods wil uitvoeren op MyOtherClass bij het opstarten van het programma, alvorens er 1 object van type MyClass wordt gemaakt? Is er ergens een soort van "initializatieblok" waar je instructies kan schrijven die altijd uitgevoerd worden bij het opstarten van het programma, alvorens je effectief objecten van MyClass begint te gebruiken? Ik moet namelijk bepaalde members van MyOtherClass initializeren zonder dat ik de constructor van MyOtherClass kan gebruiken...
 
Laatst bewerkt:
Ok, dank je, 't is me veel duidelijker nu.

Toch nog een totaal ongerelateerde vraag (niet zoveel goesting om hier nieuwe thread voor te openen):

Stel ik heb een class gemaakt met o.a. static members:

class MyClass
{
const static int i1 = 5;
static MyOtherClass* m;
}

MyOtherClass* MyClass::m = new MyOtherClass()

const statics kan je initializeren binnen de klassedefinitie, en een gewone static initializeer ik dan in de sourcecode zelf...

Maar als ik nu al enkele methods wil uitvoeren op MyOtherClass bij het opstarten van het programma, alvorens er 1 object van type MyClass wordt gemaakt? Is er ergens een soort van "initializatieblok" waar je instructies kan schrijven die altijd uitgevoerd worden bij het opstarten van het programma, alvorens je effectief objecten van MyClass begint te gebruiken? Ik moet namelijk bepaalde members van MyOtherClass initializeren zonder dat ik de constructor van MyOtherClass kan gebruiken...

in de bijhorende cpp file zet je:
PHP:
MyOtherClass MyClass::m = new MyOtherClass();
const int MyClass::i1 = 5; // de toekenning in de h file best wegdoen (-> duidelijkere code)
 
ja, dat had ik al.

Het probleem situeert zich hier:
De constructor van MyOtherClass kan bepaalde members niet initializeren via parameters, dus moet ik dit doen via het oproepen van methods op MyOtherClass. Dat kan ik echter niet doen in de bijhorende cpp file omdat er geen "initializatie" blok is dat uitgevoerd wordt bij het opstarten van het programma. Wat ik eigenlijk zou willen doen is iets dergelijks als:

PHP:
MyOtherClass* MyClass::m = new MyOtherClass(); 
MyClass::m->CallFirstMethod(parameters);
MyClass::m->CallSecondMethod(parameters);
//etc.

zodat ik zonder dat ik al één instantie van "MyClass" heb, toch al mijn MyOtherClass als static member van MyClass volledig heb geinitialiseerd (dmv constructor en bijhorende methods).
Voor alle duidelijkheid kan ik trouwens niet álle nodige parameters meegeven aan de constructor van MyOtherClass, dus ik heb weldegelijk methods nodig die ik ergens moet kunnen uitvoeren...
 
Laatst bewerkt:
ja, dat had ik al.

Het probleem situeert zich hier:
De constructor van MyOtherClass kan bepaalde members niet initializeren via parameters, dus moet ik dit doen via het oproepen van methods op MyOtherClass. Dat kan ik echter niet doen in de bijhorende cpp file omdat er geen "initializatie" blok is dat uitgevoerd wordt bij het opstarten van het programma. Wat ik eigenlijk zou willen doen is iets dergelijks als:

PHP:
MyOtherClass* MyClass::m = new MyOtherClass(); 
MyClass::m->CallFirstMethod(parameters);
MyClass::m->CallSecondMethod(parameters);
//etc.

zodat ik zonder dat ik al één instantie van "MyClass" heb, toch al mijn MyOtherClass als static member van MyClass volledig heb geinitialiseerd (dmv constructor en bijhorende methods).
Voor alle duidelijkheid kan ik trouwens niet álle nodige parameters meegeven aan de constructor van MyOtherClass, dus ik heb weldegelijk methods nodig die ik ergens moet kunnen uitvoeren...

schrijf er anders static methods voor in MyClass die parameters als argument krijgen en
dan m->blabla(parameters) oproept.

static void callFirstMethod(parameters);

void MyClass::callFirstMethod(parameters) {
m->callFirstMethod(parameters);
}
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan