Operator[] a przypisanie

0

Witajcie!
Piszę sobie pewną klasę, w której występują dynamiczne tablice dwuwymiarowe. Wszystko fajnie, tylko, że nie bardzo wiem jak mogę napisać operator indeksowania i przypisania jednocześnie?
chodzi mi o to, abym mógł wykonać coś takiego:

wsk[1][2]=0;

chyba nie mogę skorzystać po prostu z operator[], bo ona przyjmuje tylko jeden argument?
W klasie na razie nic nie ma oprócz konstruktorów i operatora wypisania:

class matrix
{
        double **wsk;
        unsigned int k,w;
        public:
        matrix(unsigned int c, unsigned int j);
        ~matrix();
        void randomize(unsigned int zakres);
        friend ostream& operator<<(ostream&, const matrix&);
};
1
  1. Lepiej zrób to za pomocą operatora (). (Może mieć dowolną ilość argumentów)
  2. Żeby móc modyfikować zwracaj referencję.

C++ FAQ [13.10] How do I create a subscript operator for a Matrix class?

0

Powinien wystarczyć operator[], niech zwróci double* np. return wsk[index];

0
byku_guzio napisał(a)

Powinien wystarczyć operator[], niech zwróci double* np. return wsk[index];

Chyba nie, albo ja coś popitoliłem:
double* matrix::operator[](unsigned int el)
{
return wsk[el];
}
Wywala to segfaulta;

0

To samo z siebie seg'a nie wywali, pokaż jak tego używasz i czy wcześniej alokujesz pamięć dla wsk?

Coś takiego mam na myśli:

class Foo
{
private:
	double **wsk;

public:
	Foo()
	{
		wsk = new double*[10];
		for(int i = 0; i < 10; i++)
		{
			wsk[i] = new double[10];
			for(int j = 0; j < 10; j++)
				wsk[i][j] = i*10+j;
		}
	}

	~Foo()
	{
		for(int i = 0; i < 10; i++)
			delete [] wsk[i];

		delete [] wsk;
	}

	double* operator[](size_t index)
	{
		return wsk[index];
	}
};
 
int main ()
{
	Foo f;

	cout << f[2][3] << endl;
	f[2][3] = 25.03;
	cout << f[2][3] << endl;

	return 0;
}
0

Powiem ci, że chyba mamy identycznie, a u mnie mimo to jest coś nie tak :|

class matrix
{
        double **wsk;
        unsigned int k,w;
        double randDouble(double low, double high);
        public:
        matrix(unsigned int c, unsigned int j);
        ~matrix();
        void randomize(unsigned int zakres);
        friend ostream& operator<<(ostream&, const matrix&);
        double* operator[](unsigned int el);
        matrix &operator=(const matrix&);

};

matrix::matrix(unsigned int c, unsigned int j)
{
    wsk=new double*[c];
    for (unsigned int i=0;i<c;i++)
        wsk[i]=new double[j];
    k=c-1;
    w=j-1;
}

matrix::~matrix()
{
    for(unsigned int i=0;i<w;i++)
        delete [] wsk[i];
    delete [] wsk;
}

void matrix::randomize(unsigned int zakres)
{
    srand(time(NULL));
    for(unsigned int i=0;i<=k;i++)
        for(unsigned int j=0;j<=w;j++)
            wsk[i][j]=1.0/(rand()%100);
}

ostream& operator << (ostream& o, const matrix& s)
{
    unsigned int k=s.k;
    unsigned int w=s.w;
    o<<"+";
    for(unsigned int i=0;i<=(k*(PRECISION+2)+8+k);i++)
        o<<"-";
    o<<"+"<<endl;

    o<<setprecision(PRECISION)<<setfill('0')<<fixed;

    for(unsigned int i=0;i<=k;i++)
    {
        o<<"| ";
        for(unsigned int j=0;j<=w;j++)
            o<<s.wsk[i][j]<<" ";
        o<<"|"<<endl;
    }
    o<<"+";
    for(unsigned int i=0;i<=(k*(PRECISION+2)+8+k);i++)
        o<<"-";
    o<<"+";

}

/*matrix &matrix::operator= (const matrix &s)
{
    for(unsigned int i=0;i<k;i++)
        for(unsigned int j=0;j<w;j++)
            wsk[i][j]=s.wsk[i][j];
}*/

double* matrix::operator[](unsigned int el)
{
    return wsk[el];
}

int main()
{
    cout << "Hello world!" << endl;
    matrix a(5,5);
    a.randomize(99);
    cout<<a;
    return 0;
}
 
0

No nie mamy identycznie. Choćby dlatego, że operatora [] w ogóle nie używasz :p

Nie wiem czym to kompilujesz, ale przykre, że to się Ci skompilowało. Masz błąd w operatorze << przez co dostajesz ten segf zapomniałeś zwrócić wartość, w tym wypadku return o;
Jeżeli dobrze kojarzę to nie zwrócenie wartości z funkcji, która deklaruje, że coś zwraca objawia się undefined behaviour, czyli może się stać cokolwiek.

Jeszcze jedno: masz błąd w destruktorze, zwalniasz o jedną tablicę za mało. W for powinno być i<=w. W ogóle ten pomysł z k i w mniejszymi o jeden od faktycznej ilości elementów jest bez sensu - zmniejsza czytelność, trzeba pamiętać w pętlach, że ma być <=, no i więcej pisania.

0

Tak, faktycznie wysłałem ci wersję "działającą" czyli akurat bez [] ;-) Po prostu zapomniałem dopisać.

Dzięki ci Dobry człowieku za wskazówki :-)
Faktycznie z tym ostream dałem ciała ;-/

Tylko kurczę chyba muszę pogrzebać w ustawieniach IDE Code::Blocks.
Bo coś mi tu nie pasuje. Normalnie jakbym kompilował poza IDE, to g++ wysypałoby ostrzeżenie, o tym, że wychodzę z funkcji nie zwracając niczego.
A kompilując w Code::Blocks nie widzę w ogóle ostrzeżeń. Dziwne. Muszę najwidoczniej gdzieś mieć wyłączone pokazywanie ostrzeżeń

0

przydałby się jeszcze konstruktor kopiujący i operator kopiowania-przypisania. w najprostszym przypadku można ich po prostu zabronić:

private:
	Foo(const Foo&);
	Foo& operator=(const Foo&);
0
Azarien napisał(a)

przydałby się jeszcze konstruktor kopiujący i operator kopiowania-przypisania. w najprostszym przypadku można ich po prostu zabronić:

private:
	Foo(const Foo&);
	Foo& operator=(const Foo&);

Jakie są konsekwencje nie zabronienia?

0

Zostaną wygenerowane automatycznie i nie będą się zachowywać tak jakbyś tego chciał - robią płytką kopię.

1

Jakie są konsekwencje nie zabronienia?

Foo raz;
if (true)
{
    Foo dwa = raz;
}
raz[1][1] = 1; // jebut!
0

Dlaczego miało by mu to wywalić, skoro konstruktor kopiujący kopiuje wszystkie składniki obiektu?

1

Przyczyna jest bardzo prosta. Skopiują się wskaźniki, odpali destruktor. Później odwołuje się do już zwolnionej pamięci.

0

Czyli konstruktor kopiujący nie kopiuje zawartości, tylko adresy pamięci? Trochę to chyba nie rozsądne

0

Kopiuje zawartość. Tylko że tą zawartością mogą być wskaźniki.

1

@Blood: jak niby kompilator ma się domyśleć co chcesz zrobić? W jaki sposób skopiować obiekt? Co tak naprawdę ma być kopiowane, a co wyliczane? Chcesz głęboką czy płytką kopię? I co ewentualnie jest pod wskaźnikami w klasie?

Dlatego właśnie domyślny konstruktor kopiujący/operator przypisania zachowuje się logicznie - kopiuje zawartość klasy. To na co pokazują wskaźniki już nie jest jej zawartością(patrząc pod kątem języka).

0

Okej okej, rozumiem.

0

w C++11 żeby było trudniej dodano jeszcze konstruktor „przesuwający” (move constructor) i odpowiadający mu operator przypisania.
ich zadaniem jest skopiowanie właśnie samych wskaźników, i wy-null-owanie ich w drugim obiekcie.

0

Zrób tak jak biali ludzie to robią - z funkcją at().

class MojaWspanialaDwuwymiarowaTablicaDouble {
public:
  double &at(unsigned int x, unsigned int y);
  const double &at(unsigned int x, unsigned int y) const;
}

//MojaWspanialaDwuwymiarowaTablicaDouble m;
m.at(12,3) = 123;

http://www.cplusplus.com/reference/stl/vector/at/

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