Wykraczam vectorem po za zakres.

0

Dzień dobry ;)
Podczas uruchomienia programu który robię wyskakuje błąd --> vector subscript out of range.
Debuger wskazał gdzie błąd ale nie takiego tam nie widzę. Możliwe że wynika to z mojej średniej znajomości vectorów wielowymiarowych
Więc po pierwsze problematyczny fragment. Dla jasności zmieniłem część zmiennych na stałe ( program nadal się wysypuje!!).

	out3.piksel.resize(3);
	//przepisanie
	out3.all_piksel.resize(256000);
	//zainicjalizwoa to konstruktorem!!

	for (int i = 0; i < 256000; i++) {
		for (int j = 0; j < 3; j++) {
			cout << "i= " << i << "   a j=" << j << endl;
			out3.all_piksel[i][j]=500 ;	
		}
	}

all_piksel to pole zadeklarowane jako:

class obraz{
public:
		vector<int> piksel;
		vector<vector<int> > all_piksel;
}

cout wskazuje że została wykonana tylko pierwsza pętla po której występuje błąd.

i = [0;255999] wskazuje na vector będący pikselem
j = [0;2] wskazuje na int będący składową
dokładnie tak jak zadeklarowałem wielkość.

Zatem w czym tkwi błąd?

W załączniku cały program

0

Do dodawania danych służy funkcja push_back. Nie ma sensu chyba za bardzo ustalać wielkości vectora, skoro potrafi on sam się dostosować do ilości danych. Nawet jeżeli ustaliłbyś wielkość za pomocą resize na 1, to przy dodaniu kolejnej wartości za pomocą funkcji push_back automatycznie wielkość Ci się zmieni ( no wiadomo, jeżeli ustalimy za pomocą resize na jakąś duża liczbę, to od razu znajdziemy miejsce dla tego vectora, zaś następne dodawanie danych będzie kosztowało, bo musimy znaleźć nowe miejsce na zmienioną wielkość vectora )

0

Wypisz sobie:
cout << out3.all_piksel[i].size() << endl;

Czyli każdy i-ty vector w all_piksel ma size() == 0, nie możesz indeksować [0, 1, 2].
Zamień [i][j] = 500 na push_back():
out3.all_piksel[i].push_back(500);

Wektor wektorów nie ma oczekiwanej długości.

A jeśli robisz macierz to możesz użyć array i po prostu indeksuj "i * j".

1
out3.all_piksel.resize(256000);

wiec rozszerzyles all_piksel[i] ktory jest vectorem vectorow. Skad wiesz ze drugi vector ma wielkosc 3? przeciez na nim nie robisz zadnego resize. (a moze nawet nie jest zainicjalizowany?)

a czemu nie lepiej po prostu dac vectorowi sie tym zajac? Czyli nie bawic sie w resize tylko po prostu push_back() i niech sam sie bawi w realokacje i zwiekszanie?
Jezeli martiwsz sie o szybkosc to mozesz od razu powiedziec ile potrzebuje zaalaokowac pamiec
new vector<int>(256000)

1

Zwiększasz rozmiar wektora piksel ale faktycznie iterujesz po wektorach znajdujących się w wektorze wektórów all_piksel. Jeśli zrobisz coś takiego

out3.all_piksel.resize(256000);
for(auto &vec : out3.all_piksel)
   vec.resize(3);

to będzie działać.

0

Możesz to również zrobić w taki sposób przy pomocy listy inicjalizatorów. Zaletą jest to, że możemy ją sobie zrobić ot tak, 'na kolanie'

int main()
{
    srand(time(NULL));
    obraz out3;
    out3.piksel.resize(3); // R,G,B
    out3.all_piksel.resize(256000);
    std::initializer_list<int> initlist;// tworzymy liste inicjalizatorow przyjmujacych typ int
    for(int i=0; i<out3.all_piksel.size(); ++i){
        initlist = {rand()%256,rand()%256,rand()%256}; // nadajemy jej jakies wartosci
        out3.all_piksel[i] = initlist; // pakujemy do all_piksel[0]
    }
    for(int i=0; i<out3.all_piksel.size(); ++i){
        for(int j=0; j<out3.piksel.size(); ++j){
            cout << out3.all_piksel[i][j] << " "; // wyswietlamy
        }
        cout << endl;
    }
}

Aaa, no i zamiast resizować wielkość w mainie, to możesz po prostu to zrobić w konstruktorze -

        obraz(){ piksel.resize(3); all_piksel.resize(256000);}
3

Robisz to źle.
Kretyński sposób naprawienia tego:

out3.all_piksel.resize(256000, std::vector<int>(3));
// albo:
out3.all_piksel = std::vector<std::vector<int>>(256000, std::vector<int>(3));

Problem polega na tym, że takie coś prowadzi do dużej fragmentacji pamięci, bo vector zawiera vector'y.

Jednym ze sposobów by to sensownie poprawić jest coś takiego:

std::vector<std::array<int, 3>> all_piksel;

Wtedy masz jeden jednolity blok pamięci i kolejne array na pewno będą ze sobą sąsiadować.

Trzeba przy tym pamiętać, że możliwe jest, że kompilator w ramach optymalizacji może wyrównać array do paragrafu (16 bajtów). Wiedza o tym jest ważna, gdyby kusił cię bezpośredni dostęp do bloku danych.

Ja bym all_piksel wypełnił w ten sposób:

const auto pixelCount = 256000;

void obraz::randomize() {
     unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
     std::default_random_engine generator (seed);
     std::uniform_int_distribution<int> distribution(0, 0x100);

     all_piksel.clear();
     all_piksel.reserve(pixelCount);
     std::generate_n(std::back_inserter(all_piksel), pixelCount, 
            [&distribution, &generator] {
            return {  distribution(generator), distribution(generator), distribution(generator) };
     });
}
0

"Czyli każdy i-ty vector w all_piksel ma size() == 0 " A dlaczego? Skoro out3.piksel.resize(3);

To czego nie widzisz to fakt, że out3.piksel i out3.all_piksel to dwie składowe klasy, które nie mają ze sobą nic wspólnego.
W pseudokodzie:
A piksel;
B<C> all_piksel;

Ustaliłeś wielkości "A" oraz "B", a indeksować chciałeś "C" (a nigdzie nie inicjalizowałeś C). A z C mają wspólny jedynie typ. Twój kod mówił tyle:

  • niech A ma długość 3
  • niech B będzie miało 256000 elementów o domyślnej wartości (a więc pusty wektor)
  • każdemu elementowi w B przypisz kolejno j-ty element (dla j < 3)

I błąd polega na tym, że w B masz puste wektory. Operator indeksowania ([]) nie sprawdza zakresów, więc jak podasz nieistniejący indeks, to się wykrzaczy. Natomiast push_back() dodaje elementy na końcu wektora.

Obrazując w skrócie:
a) twój kod

vector<int> x;
x[0] = 0; // błąd - vector jest pusty
x]1] = 1; // też błąd

b) poprawnie

vector<int> y;
y.push_back(0);
y.push_back(1);
//...
0

Okazało się że tak jak pisałem up problem

shreder221 napisał(a):

wynika to z mojej średniej znajomości vectorów wielowymiarowych

Wystarczyło prawidłowo ustalić rozmiar wektora out3.all_piksel.resize(in3.height*in3.weight,out3.piksel);
Kilka osób to zauważyło i zasygnalizowało że z tym coś jest nie tak ale będąc pewnym że ustaliłem rozmiar piksela bagatelizowałem to. A w prost nikt nie wskazał palcem błąd jest dokładnie tutaj (ew zrobiło to ale ja za mało się znam ;p Dopiero potem @MarekR22 to zrobił ale już po napisaniu tego na brudno :p ) tknęło mnie coś pisząc komentarz pod postem @fasadina

I ten fragment działa za to wykrzacza się dalej. Komunikat -"wychodzisz po za zakres wektora" Po raz pierwszy używam erase ale na programie testowym wszystko działa a w głównym jest problem.

	int licznik = 0;
	for (int i = 0; i < 256000; i++) {
		for (int j = 0; j < 3; j++) {
			if (out3.all_piksel[i - licznik][j]==500) {
				out3.all_piksel.erase(out3.all_piksel.begin() + i-licznik); //  <--- tutaj wychodzę
				licznik++;
//				break;
			}
		}
	}
0

Co Ty tam właściwie chcesz zrobić? Takie używanie erase w pętli bardzo ciężko jest racjonalizować, użyj po prostu std::remove_if wraz z erase.

1

Dla i = 0 i licznik > 0 próbujesz usunąć elementy sprzed tablicy.
tablica[początek + 0 - 1] -> usuń tabica[-1].

PS: używaj debuggera do podglądania danych w czasie wykonywania programu.

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