Przenoszenie unikalnych wskaźników pomiędzy kontenerami z użyciem konstruktora kopiującego
Ostatnio zmodyfikowano 2018-04-18 20:58
NiNJAxFREEZu Temat założony przez niniejszego użytkownika |
Przenoszenie unikalnych wskaźników pomiędzy kontenerami z użyciem konstruktora kopiującego » 2018-04-18 20:34:17 Witam wszystkich. Mam pewien problem natury obiektowo-wskaźnikowej. Za pomocą unique pointerów (i koniecznie korzystając z konstruktora przenoszącego) przenieść z jednego kontenera unique pointerów do typu klasowego do drugiego oczywiście bez kopiowania. Kod prezentuję się tak: #include <iostream> #include <memory> #include <vector> using namespace std;
class Parent { public: int a; int b; Parent() { } Parent( int a, int b ) { this->a = a; this->b = b; } Parent( const Parent & copy ) { this->a = copy.a; this->b = copy.b; std::cout << "Konstruktor kopiujacy -> Parent\n"; } Parent( Parent && p ) : a( std::move( p.a ) ) , b( std::move( p.b ) ) { std::cout << "Konstruktor przenoszacy -> Parent\n"; } virtual int getSum() { return a + b; } };
class Sub : public Parent { public: int c; Sub() { } Sub( int a, int b, int c ) { this->a = a; this->b = b; this->c = c; } Sub( const Sub & copy ) { this->a = copy.a; this->b = copy.b; this->c = copy.c; std::cout << "Konstruktor kopiujacy -> Sub\n"; } Sub( Sub && s ) { Sub::a = std::move( s.a ); Sub::b = std::move( s.b ); Sub::c = std::move( s.c ); std::cout << "Konstruktor przenoszacy -> Sub\n"; } int getSum() { return a + b + c; } };
using namespace std; typedef std::vector < std::unique_ptr < Parent >> Kontener;
int main() { Kontener kontener1, kontener2; kontener1.push_back( make_unique < Parent >( 1, 1 ) ); kontener1.push_back( make_unique < Parent >( 2, 2 ) ); kontener1.push_back( make_unique < Sub >( 1, 1, 1 ) ); kontener1.push_back( make_unique < Sub >( 2, 2, 2 ) ); for( int i = 0; i < kontener1.size(); ++i ) cout << kontener1[ i ]->getSum() << endl; system( "pause" ); system( "cls" ); kontener2.push_back( make_unique < Sub >( move( kontener1[ 2 ] ) ) ); system( "pause" ); return 0; }
Sytuacja wygląda tak. Gdyby zamiast linijki oznaczonej gęstymi znakami zapytania w komentarzu umieścić w nawiasach push_back() samo "move(...)" to rzeczywiście w drugim kontenerze pojawi się nasz wskaźnik. Ale nie wywoła się konstruktor przenoszący ani kopiujący oraz próba odczytu danych z kontenera1 wywala wyjątek w momencie, gdy pętla dojdzie do wartości usunietej(?), oczywiście zwykły if == nullptr załatwia sprawę, ale dalej żadnego echa od konstruktora przenoszącego. Więc moje pytanie brzmi -> Jak wywołać przy przenoszeniu konstruktor przenoszący? |
|
RazzorFlame |
» 2018-04-18 20:58:15 Gdyby (...) umieścić w nawiasach push_back() samo "move(...)" to rzeczywiście w drugim kontenerze pojawi się nasz wskaźnik. Ale nie wywoła się konstruktor przenoszący ani kopiujący |
Konstruktor przenoszący jest wywoływany, ale nie dla klasy Parent czy Sub tylko dla std::unique_ptr. Unique pointer właśnie tak jest skonstruowany, że nie można go skopiować, ale można przenieść. std::unique_ptr może, w uproszczeniu wyglądać jakoś tak: template < typename T > class unique_ptr { public: unique_ptr( T * ptr ) : m_ptr( ptr ) { } unique_ptr( unique_ptr && other ) : m_ptr( other.m_ptr ) { other.m_ptr = nullptr; } unique_ptr( const unique_ptr & other ) = delete; private: T * m_ptr; };
Kiedy wywołujesz std::move na obiekcie typu std::unique_ptr to pozwalasz innemu unique pointerowi zabrać sobie wskaźnik, którego tamten był właścicielem. Wywołuje się konstruktor przenoszący, ale dla std::unique_ptr. oraz próba odczytu danych z kontenera1 wywala wyjątek w momencie, gdy pętla dojdzie do wartości usunietej(?) |
Kiedy używasz semantyki przeniesienia, to po wykonaniu przeniesienia zawartości z A do B nie wolno Ci traktować A tak, jakby wciąż posiadał poprawną wartość. Najprawdopodobniej w std::unique_ptr dzieje się to, co pokazałem u góry w kodzie - w momencie przeniesienia, m_ptr dawnego właściciela staje się nullptr przez co potem próbujesz odwołać się do adresu zerowego, co skutkuje crashem. Jak wywołać przy przenoszeniu konstruktor przenoszący? |
Przeprojektuj swój kod, bo troche źle zrozumiałeś ideę przenoszenia i unique pointerów. |
|
« 1 » |