• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Semantyka przenoszenia w C++ - trzy pytania

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
+1 głos
137 wizyt
pytanie zadane 27 marca w C i C++ przez whiteman808 Gaduła (4,760 p.)
edycja 28 marca przez whiteman808

Hej,

Dlaczego w przypadku używania std::move nie tworzy się osobnych konstruktorów tak jak pokazano to w // 1 i w // 2 tylko zwyczajnie używa się przekazywania przez wartość?

Przypadek // 1 w którym przekazujemy zwykłe l-wartości jestem w stanie zrozumieć, wtedy po prostu konwertujemy f i l za pomocą std::move na r-wartości i wywołujemy odpowiednie konstruktory przenoszące odpowiadających im klas skoro mamy r-wartości (std::move dokonuje konwersji przekazanego mu argumentu na r-wartość żeby można było go przenieść).

Nie rozumiem natomiast tego czemu nie tworzymy analogicznej funkcji jak pokazano w // 2 przyjmującej referencje do r-wartości. Przecież przekazując przez wartość std::string("Andrzej") do konstruktora // 1 skoro mamy przekazywanie przez wartość a nie referencję to i tak dokonywana jest kopia tego obiektu. Konkretnie tworzona jest obiekt tymczasowy i to co jest w tym obiekcie jest przenoszone do firstname i lastname. Gdyby użyć referencji do r-wartości to nie byłoby tworzonego żadnego obiektu tymczasowego.

Drugie moje pytanie dotyczy czy dobrze rozumiem dlaczego w kodzie załączonym do tego pytania mamy na wyjściu , , 12. Według mnie wyjście jest takie ponieważ w przypadku std::string zostały przeniesione zasoby powiązane z obiektem natomiast age nie otrzymał przypadkowej wartości dlatego że w tym przypadku age nie jest obiektem zarządzanym. Semantyka przenoszenia ma sens jedynie w odniesieniu do zasobów alokowanych dynamicznie przez new i delete lub w podobny sposób, zarządzanych przez instancje klas. W przypadku zwykłych intów czy floatów nie mamy odpowiedzialności za zwolnienie obiektu. Przeniesienie polega na transferze odpowiedzialności za zwolnienie zasobu. Ddobrze to rozumiem?

Trzecie pytanie dotyczy tego czy referencje do r-wartości wewnętrznie też są implementowane jako wskaźniki tak jak zwykłe l-wartościowe referencje.

Dziękuję i pozdrawiam,
whiteman808

~ ❯ cat main.cpp                                                                                                                                ✘ INT 19:30:01
#include <iostream>
#include <string>

class person {
public:
    person() : firstname{}, lastname{}, age{0} {}
    person(std::string f, std::string l, int a) // 1
        : firstname{std::move(f)}, lastname{std::move(l)}, age{a} {
        std::cout << f << ", " << l << ", " << a << '\n';
    }
    person(std::string&& f, std::string&& l, int a) // 2
        : firstname{std::move(f)}, lastname{std::move(l)}, age{a} {
        std::cout << f << ", " << l << ", " << a << '\n';
    }
    person(const person& p) { // konstruktor kopiujący
        firstname = p.firstname;
        lastname = p.lastname;
        age = p.age;
    }
private:
    std::string firstname;
    std::string lastname;
    int age;
};

int main() {
    person p{"Jan", "Kowalski", 12};
    return 0;
}
~ ❯ ./main                                                                                                                                            19:30:04
, , 12
komentarz 27 marca przez mokrowski Mędrzec (158,660 p.)
Z jakiej książki korzystasz do nauki języka C++?
1
komentarz 28 marca przez whiteman808 Gaduła (4,760 p.)

Czytam https://stackoverflow.com/questions/3106110/what-is-move-semantics

Czy dobrze rozumiem, że nie ma potrzeby robienia person(std::string&& f, std::string&& l, int a) ponieważ od C++11 jak przekazujemy argument przez wartość to kompilator sam decyduje czy zainicjalizować przekazywany obiekt poprzez konstruktor kopiujący jak przekazujemy funkcji l-wartość, czy przez konstruktor przenoszący w przypadku r-wartości?

Przekazując r-wartość do // 1 po prostu przenosimy r-wartość std::string("costam") do zmiennej typu std::string tworzonej w trakcie wywoływania funkcji?

komentarz 28 marca przez TOWaD Mądrala (6,480 p.)
edycja 28 marca przez TOWaD

C++11 jak przekazujemy argument przez wartość to kompilator sam decyduje czy zainicjalizować przekazywany obiekt poprzez konstruktor kopiujący jak przekazujemy funkcji l-wartość, czy przez konstruktor przenoszący w przypadku r-wartości?

Mi się wydaje że tak. Na cpp Polską były 4 artykuły o tym.. https://cpp-polska.pl/post/zarzadzanie-zasobami-w-c-2-semantyka-przenoszenia-stdmove

Ps. Oczywiście jak jest r-wartością

komentarz 28 marca przez mokrowski Mędrzec (158,660 p.)
Sama zasada wyboru, choć zawiła jest deterministyczna: https://en.cppreference.com/w/cpp/language/move_constructor

Ogólnie, w każdym przypadku w którym w trakcie przeniesienia obiektu możesz wybrać konstruktor/operator kopiujący i masz do dyspozycji konstruktor/operator przenoszący, C++ preferuje przenoszący mając nadzieję że sam fakt jego istnienia oznacza że programista przewidział szybszą obsługę operacji. Możesz to sprawdzić tworząc klasę która wydrukuje na konsole komunikat w przypadku wywołania odpowiednich konstruktorów/operatorów. Inicjuj std::vector takimi obiektami i sprowokuj realokację pamięci. Zobaczysz co się będzie działo w przypadku posiadania 1, jednego z oraz 2 konstruktorów/operatorów.

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

+1 głos
3 odpowiedzi 371 wizyt
pytanie zadane 22 czerwca 2017 w HTML i CSS przez lagarto Nowicjusz (200 p.)
–1 głos
1 odpowiedź 498 wizyt
0 głosów
0 odpowiedzi 1,747 wizyt

93,440 zapytań

142,432 odpowiedzi

322,679 komentarzy

62,802 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

...