Konstruktor przenoszenia

0

Witam, mam taki o to przykładowy kod:

 
#include <iostream>
#include <string>
using namespace std;
class Example6 {
    string* ptr;
public:
    // wskaŸnik na string jest inicjowany adresem obiektu typu string(pustego
     Example6(const string& str): ptr(new string(str)) {cout << "wywolano zwykly konstruktor" << endl;}
    // wskaznik jest inicjowany obiektem typu string o zawartosci znakow przeslanych w parametrze str
     Example6 (const Example6& x) : ptr(new string(x.content())) {cout << "wywolano konstruktor kopiujacy"<<endl;}
     Example6& operator= (const Example6& x){

           delete ptr;
           ptr = new string (x.content());
           return *this;

    }
    // bedzie dzialac tak samo jak powyzsze rozwiazanie
    // roznica jest taka, ze tutaj nie kasujemy starego obiektu, tylko kopiujemy zawartosc zawartosci wskaznika
    /*Example5& operator= (const Example5& x){
        //
        *ptr = x.content();
        return *this;
    }*/

     // moving constructor
     Example6(Example6&& x) : ptr(x.ptr){
        *ptr = "... jasiu";
        x.ptr = nullptr;
        }
     // operator przypisania
     Example6& operator= (Example6&& x){
         // operator przenoszenia
         cout <<"wywolano operator przenoszenia"<<endl;
         delete ptr;
         ptr = x.ptr;
         // czyszczenie tego co jest pod x, tymczasowym obiektem
         x.ptr = nullptr;
         return *this;
     }
     ~Example6 () {delete ptr; cout <<"wywolano destruktor"<<endl;}
     // konstruktor kopiujacy, ktory zwraca wartosc a nie wskaznik
    const string& content() const {return *ptr;}
    void set_string(string str){ *ptr = str;}
    Example6 operator+(const Example6& rhs){
        return Example6(content() + rhs.content());
    }

};
int main(){

    Example6 foo("ss");
    Example6 bar = Example6("abc");
    cout << bar.content() << endl;
  //  foo = foo + bar;

   // cout << "foo's content: " << foo.content() << '\n';
   return 0;

}

W momencie kodu:

 Example6 bar = Example6("abc");

powinien zostać użyty konstruktor przenoszenia(ang. move-constructor). Nie wiem jednak dlaczego uruchamiany jest zwykły konstruktor.
Może mi ktoś wyjaśnić dlaczego tak się dzieję? Używam standardu c++11.

0

Ty masz jedynie zdefiniowany move constructor dla Example6, nie masz za to move constructor przyjmującego string

0

Myślałem, że to działa tak, że najpierw tworzy się obiekt tymczasowy za pomocą konstruktora klasy Example6 z jakimś tam napisem. Następnie wywoływany jest konstruktor prznoszenia klasy Example6.

0

powinien zostać użyty konstruktor przenoszenia(ang. move-constructor). Nie wiem jednak dlaczego uruchamiany jest zwykły konstruktor.

Bo nie ma potrzeby, by działo się inaczej. Skoro widać że chcesz skonstruować obiekt pod zmienną bar, to kompilator to robi - nie ma potrzeby by tworzyć zmienną tymczasową i od razu ją przenosić.

http://en.wikipedia.org/wiki/Copy_elision

0

No tak już na to raz napotkałem w jednym tutorialu, że to sprawa optymalizacji czyli jeżeli nie ma potrzeby to taki konstruktor przenoszenia nie będzie wywołany. Czy można jakoś świadomie na 100 % wywołać ten konstruktor? Bo czasami są przypadki gdzie kopiowanie a przenoszenie to zupełnie dwie sprawy.

0
#include <iostream>
#include <utility>
using namespace std;

class Foo {
public:
	Foo() {}
	Foo(const Foo&) = delete;
	Foo& operator=(const Foo&) = delete;
	Foo(Foo&& f) { cout << "move ctor"; }
    Foo& operator=(Foo&& f) { cout << "move operator"; return *this; }
    
};

void f(Foo&& f) {}

int main() {
	Foo f1 = move(Foo());
	return 0;
}
0

Bo czasami są przypadki gdzie kopiowanie a przenoszenie to zupełnie dwie sprawy.
Ale kod powinien być tak napisany, by nie miało to znaczenia na wynik programu - ewentualnie tylko na jego wydajność.

PS. chyba że chcemy wykorzystać idiom movable but not copyable, ale wtedy tak jak @n0name_l pokazał, blokujemy kopiowanie a pozwalamy tylko na przenoszenie.

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