operator=() przenoszący c++11
Ostatnio zmodyfikowano 2016-05-17 00:47
mateczek Temat założony przez niniejszego użytkownika |
operator=() przenoszący c++11 » 2016-05-16 15:05:39 Chciałem sprawdzić na przykładzie coś co wyczytałem odnośnie referencji && na R-Value, konstruktorów przenoszących, i przenoszącego operatora przypisania. Napisałem klasę do mnożenia macierzy. PS. macierz 2D trzymam w tablicy jednowymiarowej by łatwiej operować pamięcią #include <iostream>
using namespace std; class matrix { int * tab = NULL; int wiersze = 0, kolumny = 0; public: friend ostream & operator <<( ostream & s, matrix & m ); matrix( int w, int k ) : wiersze( w ) , kolumny( k ) { cout << "jestem konstruktor" << endl; int rozmiar = w * k; tab = new int[ rozmiar ]; } matrix() { } ~matrix() { if( tab ) { delete[] tab; tab = NULL; } } int & operator ()( int w, int k ) { return tab[( w - 1 ) * kolumny + k - 1 ]; } int row() { return wiersze; } int column() { return kolumny; } matrix & operator =( matrix && wzor ); matrix( const matrix & wzor ); matrix operator *( matrix & m ); matrix & operator =( const matrix & wzor ); };
matrix & matrix::operator =( matrix && wzor ) { cout << "jestem operator przenoszenia" << endl; tab = wzor.tab; wiersze = wzor.wiersze; kolumny = wzor.kolumny; wzor.tab = NULL; wzor.wiersze = 0; wzor.kolumny = 0; return * this; }
matrix::matrix( const matrix & wzor ) { cout << "jestem konstruktor kopiujący" << endl; wiersze = wzor.wiersze; kolumny = wzor.kolumny; int rozmiar = wiersze * kolumny; tab = new int[ rozmiar ]; for( int i = 0; i < rozmiar; i++ ) { tab[ i ] = wzor.tab[ i ]; } }
matrix & matrix::operator =( const matrix & wzor ) { cout << "jestem operator przypisania" << endl; wiersze = wzor.wiersze; kolumny = wzor.kolumny; int rozmiar = wiersze * kolumny; if( tab ) delete[] tab; tab = new int[ rozmiar ]; for( int i = 0; i < rozmiar; i++ ) { tab[ i ] = wzor.tab[ i ]; } }
matrix matrix::operator *( matrix & m ) { if( kolumny == m.wiersze ) { matrix temp( wiersze, m.kolumny ); for( int w = 1; w <= temp.wiersze; w++ ) { for( int k = 1; k <= temp.kolumny; k++ ) { int element = 0; for( int i = 1; i <= kolumny; i++ ) element += operator ()( w, i ) * m( i, k ); temp( w, k ) = element; } } return temp; } cout << "nie da sie pomnorzyc" << endl; }
ostream & operator <<( ostream & s, matrix & m ) { for( int w = 1; w <= m.wiersze; w++ ) { for( int k = 1; k <= m.kolumny; k++ ) { s << m( w, k ) << " "; } s << endl; } return s; }
int main() { matrix m1( 5, 5 ); matrix m2( 5, 4 ); for( int w = 1; w <= m1.row(); w++ ) { for( int k = 1; k <= m1.column(); k++ ) { m1( w, k ) = 1; } } cout << m1 << endl; for( int w = 1; w <= m2.row(); w++ ) { for( int k = 1; k <= m2.column(); k++ ) { m2( w, k ) = 2; } } cout << m2 << endl; matrix m3; m3 = m1 * m2; cout << m3 << endl; }
wynik działania programu https://zapodaj.net/images/e6f7041f2504a.png jestem konstruktor jestem konstruktor 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
jestem konstruktor //w funkcji operator*() tworzony jest obiekt tymczasowy OK jestem konstruktor kopiujący //ten konstruktor nie powinien się pojawić bo chciałem tylko przenieść tablicę a nie ją kopiować NOK jestem operator przenoszenia //ostateczne przypisanie OK 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
Zainteresowała mnie możliwość przenoszenia samych wskaźników na bufor zadeklarowany dynamicznie. Z tąd właśnie moje zapytanie do kodu matrix m1( 5, 5 ); matrix m2( 5, 4 );
matrix m3;
m3 = m1 * m2;
Jednak gdzieś między konstrukcją obiektu tymczasowego w funkcji operatror*() a przenoszącym operatorem przypisania, Uruchamia się konstruktor kopiujący. Ten konstruktor kopiujący sprawia, że cały zysk możliwości przeniesienia tylko samego wskaźnika na dynamiczną tablicę idzie w diabły. Moje pytanie jest następujące co źle robię ?? i gdzie można lepiej PS. Programik z macierzami napisałem dla empirycznego sprawdzenia nowej dla mnie metody przenoszenia dynamicznie alokowanych tablic |
|
Monika90 |
» 2016-05-16 17:02:36 Nie masz konstruktora przenoszącego matrix(matrix&& wzor), więc kompilator używa kopiującego. cout << "nie da sie pomnorzyc" << endl;
|
Tak nie można, jeżeli nie da się zwrócić poprawnej wartości to rzuć wyjątkiem. |
|
mateczek Temat założony przez niniejszego użytkownika |
» 2016-05-16 17:52:31 nie masz konstruktora przenoszącego matrix(matrix&& wzor)
|
Dzięki wielkie za wskazówkę zaraz przetestuje. Tylko jeszcze doczytam na temat std::move, którego zaleca się używać w konstruktorach przenoszących. |
|
j23 |
» 2016-05-16 18:21:54 matrix & matrix::operator =( matrix && wzor ) { tab = wzor.tab; ... } |
A co jeśli this.tab nie jest null? |
|
mateczek Temat założony przez niniejszego użytkownika |
» 2016-05-17 00:47:32 Dzięki jeszcze raz Monika Dopisanie konstruktora przenoszącego faktycznie spowodowało, że zamiast konstruktora kopiującego odpalił się przenoszący. A dodanie wyjątku jeszcze lepiej zadziałało. Bo żaden z nich nie był potrzebny. matrix matrix::operator *( matrix & m ) { if( kolumny != m.wiersze ) throw "nie pomnozysz takich macierzy"; matrix temp( wiersze, m.kolumny ); for( int w = 1; w <= temp.wiersze; w++ ) { for( int k = 1; k <= temp.kolumny; k++ ) { int element = 0; for( int i = 1; i <= kolumny; i++ ) element += operator ()( w, i ) * m( i, k ); temp( w, k ) = element; } } return temp; } int main() { matrix m3; try { m3 = m1 * m2; cout << m3 << endl; } catch( char const * p ) { cout << p << endl; } }
wynik zadowalający: jestem konstruktor jestem konstruktor 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
jestem konstruktor // tutaj konstruktor obiektu tymczasowego jestem operator przenoszenia // i operator przeniesienia 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
@j23
matrix & matrix::operator =( matrix && wzor ) { tab = wzor.tab; ... }
A co jeśli this.tab nie jest null? }
|
Słuszna uwaga. Będzie wyciek pamięci;) Przenosząc powinienem skorzystać z std::swap (zamiana). Wówczas z obiektem tymczasowym uporają się mechanizmy niszczenia obiektów tymczasowych. |
|
« 1 » |