Alokacja tablicy <vector> – przekroczenie pamięci?

0

Piszę Adaline z użyciem wektorów. Kod jak poniżej:

    void Adaline::fillArrays()
    {
    	for (int i = 0; i < numberOfNeurons; i++)
    	{
                neuron[i].tabX.reserve(numberOfSignals);
    		neuron[i].output = 0;
    		neuron[i].z = 0;
    		neuron[i].y = -1;
    	}
    
    	// przypisanie wartości do sieci
    	for (int i = 0; i < numberOfNeurons; i++)
    	{
    		for (int j = 0; j < numberOfSignals; j++)
    		{
    			cout << "Enter signal [" << i << "," << j << "]: "; cin >> neuron[i].tabX[j];
    			neuron[i].wX.push_back(0.2+ 0.1*(j+1) - 0.08*(i+1));
    			neuron[i].dW.push_back(0);
    		}
    		cout << "Enter expected output: "; cin >> neuron[i].z;
    	}
    }

Pojawiają się dziwne błędy pokroju:

+ message 0x01240288 L"vector subscript out of range" const wchar_t *

lub:

    _STD_BEGIN
    
    #ifdef _DEBUG
    _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Debug_message(const wchar_t *message, const wchar_t *file, unsigned int line)
    	{	// report error and die
            if(::_CrtDbgReportW(_CRT_ASSERT, file, line, NULL, L"%ls", message)==1)
            {
                ::_CrtDbgBreak();
            }
    	}
    _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Debug_message(const unsigned short *message, const unsigned short *file, unsigned int line)
    	{	// report error and die
            _Debug_message((wchar_t *) message, (wchar_t *) file, line);
    	}
    
    #endif
    
    _STD_END

Ma ktoś ideę, o co tutaj chodzi? Podejrzewam, że standardowo problem z pamięcią.

1

A czy na pewno nigdzie nie przekraczasz zakresu wektora? ;p

1

numberOfNeurons na pewno odpowiada neuron.size()? Wypisz sobie neuron.size() na początku tej metody, albo debuguj i zobacz co zwróci.

0

Oto kawałek kodu obrazujący alokację pamięci dla "neuron":

 	iterations = 100;
	numberOfNeurons = 2; // important
	numberOfSignals = 3; // important
	eta = 0.6;

	neuron.reserve(numberOfNeurons);

	fillArrays();
	Delta();

Faktycznie wynosi zero jak sprawdzam rozmiar, chociaż nie wiem jakim cudem. Warto zwrócić uwagę, że neuron jest klasy "Neuron" i może tutaj gdzieś jest problem? Z drugiej strony, na chłopski rozum powinien zaalokować 2 obiekty klasy "Neuron".

2

Na chłopski rozum to właśnie nie powinien. Dokumentację poczytaj: http://en.cppreference.com/w/cpp/container/vector/reserve
I tu jeszcze: http://en.cppreference.com/w/cpp/container/vector/resize

0

Wracając więc z podróży. Aktualnie alokacja przestrzeni oraz wartości dla wektora neuronów wygląda tak:

void Adaline::fillVector(vector <Neuron>& neurons)
{
	for (int i = 0; i < numberOfNeurons; i++)
	{
		Neuron neurony;
		neurony.output = 0;
		neurony.z = 0;
		neurony.y = -1;
		
		for (int j = 0; j < numberOfSignals; j++)
		{
			neurony.tabX.push_back(0);
			cout << "Enter signal [" << i << "," << j << "]: "; cin >> neurony.tabX[j];
			neurony.wX.push_back(0.2 + 0.1*(j + 1) - 0.08*(i + 1));
			neurony.dW.push_back(0);
		}
		cout << "Enter expected output: "; cin >> neurony.z;
		neurons.push_back(neurony); // wpisujemy pierwszy (kolejny) wektor do naszej głównej tablicy neuronów
	}

	Delta(neurons);

}

Lokalnie tworzymy klasę Neurony neurony, wpisujemy wszystkie wartości do naszego głównego neurons (neurons.push_back(neurony);), którą to wartość zachowujemy. Następnie przekazujemy neurons do reguły delta, gdzie realizujemy całą sieć Madaline. Jak zachowuje się program: alokuje poprawnie rozmiary każdego z wektorów (także wektorów <float> i <int> klasy Neuron), wpisuje także poprawnie wejściowe sygnały tabX (najpierw alokujemy miejsce z wartością zero, a potem wpisujemy tam wartość), ale już niepoprawnie wpisuje wartości wagowe wX. Po prostu wpisuje tam same zera, nie wiedzieć czemu. Jakiś pomysł, co z tym zrobić?

0
        Neuron neurony;
        neurony.output = 0;
        neurony.z = 0;
        neurony.y = -1; 

Ile masz neuronów w jednym neuronie? ;P Jeden? To dlaczego nazwany "neurony"? :P (chyba, że to "neuron igrek"?) Co ważniejsze - rozejrzyj się za pojęciem "konstruktor". Za każdym razem tak ręcznie przypisujesz wartości początkowe neuronów?

void Adaline::fillVector(vector <Neuron>& neurons) 

Czyyyyli z zewnątrz przyjmujesz ten vector? Coś mi się zdaje, że niepotrzebny ten parametr, bo Ci tylko nazwą przesłania this->neurons. Zadziałałoby jeszcze, jeśli wołałbyś to z "wewnętrznym" vectorem w parametrze, ale zawołania nam nie wkleiłeś, to nic na ten temat nie wiemy.

"Lokalnie tworzymy klasę " - nie klasę, a instancję, obiekt klasy.
"najpierw alokujemy miejsce z wartością zero, a potem wpisujemy tam wartość" - oj... ech. :P Nie. neurony.output już sobie szczęśliwie istnieje, bo obiekt neurony został już skonstruowany. Przypisujesz tam wartość, owszem, ale żadna alokacja pamięci nie ma już miejsca.

Jakiego typu jest Neuron::wX?

0

W porządku. Odnośnie konstruktorów i zabierania parametrów z zewnątrz – póki co chcę przetestować działanie tych wektorów, potem się zająć całym upiększaniem (to raczej zgodne z taksonomią Blooma, że najpierw nabiera się wiedzy o sadzeniu kwiatów, a potem dba się o stylistykę ogrodu, niemniej staram się zrozumieć nieodpartą pokusę wykazania niewiedzy skądinąd początkującego programisty).

Xupicor napisał(a):

"najpierw alokujemy miejsce z wartością zero, a potem wpisujemy tam wartość" - oj... ech. :P Nie. neurony.output już sobie szczęśliwie istnieje, bo obiekt neurony został już skonstruowany. Przypisujesz tam wartość, owszem, ale żadna alokacja pamięci nie ma już miejsca.

Tu akurat odnosiłem się do tabX.:)

class Neuron {
public:
	vector <int> tabX;
	vector <float>  wX;
	vector <float>  dW;
	float output;
	float z;
	int y;
};

Klasa Neuron wygląda tak. Wszystkie rozmiary wektorowe alokowane są poprawne – nie wpisują się jednak poprawnie wartości do wX (jedynie same zera).

1

Sure, najpierw się naucz używać, a potem dobrze używać - ale może warto by było zacząć od dobrze używać, żeby się nie "oduczać" potem? Szczególnie, jeśli sam się uczysz, bo nie będzie komu Cię potem skorygować. ;) To w ogóle temat rzeka, nie miejsce i nie czas.

Tu akurat odnosiłem się do tabX.:)
Wszystko jedno. Pamięć używana przez tabX to część pamięci obiektu, więc w momencie gdy kontrola wchodzi w ciało konstruktora obiektu - cała ta pamięć jest już zaalokowana. Pamięć pod elementy tabX to inna sprawa.

Po prostu miej świadomość, że rzucasz na lewo i prawo słowami, które mają pewne ścisłe znaczenia, a składasz je do kupy w taki sposób, że nie tylko nie da się ukryć, żeś pan początkującym, ale po prostu ciężko to zignorować. Jeśli wszyscy to zignorują, jeszcześ gotów pomyśleć, że wszystko jest w porządku. My na tym nie stracimy - ale Ty nie zyskasz. :P

No ale wracając... Hmmm, jak wywołujesz tę metodę?

0

Masz rację – lepiej się uczyć na "czystym" kodzie niż zasyfionym jak u mnie, ale powiem szczerze, że najpierw chcę "skumać" do końca ten vector i sposób implementacji, a potem zrekonstruować wszystkie powiązania między klasami i metodami. Odnośnie poprawiania mnie co do nazewnictwa – jak najbardziej, i dobrze, że to podkreślasz, bo przy okazji ciągle się uczę:).

Odnośnie wywołania metody, wygląda to tak:

Adaline::Adaline()
{
	iterations = 100;
	numberOfNeurons = 2;
	numberOfSignals = 3; 
	eta = 0.6;

	fillVector(neurony);
}

Więc, po stworzeniu w main obiektu Adaline adaline konstruktor domyślny automatycznie stworzy wektor dla naszej sieci vector <Neuron> neurony (tak zapis wygląda w definicji klasy). neurony od razu przekazujemy do funkcji fillVector (zapisana powyżej), która następnie wywołuje funkcję z regułą delta, a funkcja z regułą delta wywołuje wyświetlanie (trochę pozagnieżdżałem, każda następna funkcja jest w funkcji poprzedzającej, ale kod całkiem sprawnie się czyta). Problem w tym, że neurony.wX.push_back(0.2 + 0.1(j + 1) - 0.08(i + 1));** nie przypisuje żadnej wartości poza zerem. A według wikibooks:

vector<int> tab;
cin >> n;
for( int i=0; i<n; ++i )
{
   int element;
   cin >> element;
   tab.push_back(element);
}

podobna składnia powinna ładniutko wpisywać element na końcu naszego wektora. Niestety u mnie wpisuje same zera.

1
    fillVector(neurony);

Okej, czyli przesyłasz do tej metody zmienną przez parametr, ale w zasadzie niepotrzebnie, bo masz we wszystkich metodach tej klasy dostęp bezpośredni do tej zmiennej.

Zbierzmy to do kupy troszkę:

class Neuron {
public:
    vector <int> tabX;
    vector <float>  wX;
    vector <float>  dW;
    float output; // zainicjalizuj tę i poniższe wartości, patrz niżej
    float z; 
    int y;
    
    Neuron() : output(0), z(0), y(-1) { } // inicjalizacja danych za pomocą listy inicjalizacyjnej konstruktora.
};

Adaline::Adaline()
{
    iterations = 100;
    numberOfNeurons = 2;
    numberOfSignals = 3; 
    eta = 0.6;
 
    fillVector(neurony);
}

void Adaline::fillVector(vector <Neuron>& neurons) // ten parametr wygląda na niepotrzebny
{
    for (int i = 0; i < numberOfNeurons; i++)
    {
        Neuron neurony; // przysłaniasz this->neurony, przesłany za pomocą parametru - dość to dziwne, takie "dookoła stodoły, przez strych do piwnicy"
        neurony.output = 0; // to powinno być załatwione przez konstruktor klasy Neuron
        neurony.z = 0;
        neurony.y = -1;
 
        for (int j = 0; j < numberOfSignals; j++)
        {
            neurony.tabX.push_back(0);
            cout << "Enter signal [" << i << "," << j << "]: "; cin >> neurony.tabX[j];
            neurony.wX.push_back(0.2 + 0.1*(j + 1) - 0.08*(i + 1));
            neurony.dW.push_back(0);
        }
        cout << "Enter expected output: "; cin >> neurony.z;
        neurons.push_back(neurony); // wpisujemy pierwszy (kolejny) wektor do naszej głównej tablicy neuronów
    }
 
    Delta(neurons); // znowu, ten parametr pewnie niepotrzebny - po prostu dobieraj się do `neurony` bezpośrednio
 
}

W ogóle kod jest do przepisania, bo na ten przykład powinieneś Neurona "zamknąć". Enkapsulacja to dość ważny temat - raczej nie powinniśmy tak grzebać w Neurona flakach. Poza tym kod zrobiłby się krótszy i bardziej czytelny tam gdzie to ma największe znaczenie. No ale zdaję sobie sprawę, że w pięć minut się nie nauczysz wszystkiego. Sam pisałem dużo gorszy kod, na dużo mniej ciekawe tematy. :P

Hm. Konstruktor kopiujący w Neuron masz wygenerowany automatycznie, więc ten push_back powinien zadziałać normalnie... Hm. Kawa już dawno wyparowała, nic mi nie przychodzi do głowy. :P Próbuj wyrzucać wszystko co niepotrzebne, żeby sklecić z kodu jak najmniejszy program reprezentujący problem, który da się skompilować. Jeśli sam nie znajdziesz źródła problemu - a możliwe, że takim sposobem znajdziesz - wklej tutaj.

1 użytkowników online, w tym zalogowanych: 0, gości: 1