zwracanie wartości

0

Cześć :)
Mamy następującą funkcję:

vector<int> func() {
vector<int> Vec;
//wypelniamy go
return Vec;
}
int main(){
vector<int> vec2= func(); //1
func(); //2 
}

Pytanie do komenatarza nr 1:
Chciałbym dowiedzieć się jak odbywa się zwracanie wartości? Z tego co pamiętam, to zwracana wartość wędruje na stosie. Co dalej się z nią dzieje? Widać, że w pierwszym wywołaniu jej wartość zostaje zapamiętana, a w drugim nie. Jak to wygląda dla tych dwóch różnych sytuacji?

Pytanie drugie:

Program 1:
vector<int> func() {
vector<int> Vec;
//wypelniamy go
return Vec;
}
int main(){
vector<int> vec2= func(); 

}

Program 2:
vector<int> func() {
vector<int> Vec;
//wypelniamy go
return Vec;
}
int main(){

func(); 
}

Po disassemblowaniu kodu funkcji main() wygląda kod następująco:

 0x0000000000400682 <+0>:   push   %rbp
   0x0000000000400683 <+1>: mov    %rsp,%rbp
   0x0000000000400686 <+4>: sub    $0x20,%rsp
   0x000000000040068a <+8>: lea    -0x20(%rbp),%rax
   0x000000000040068e <+12>:    mov    %rax,%rdi
   0x0000000000400691 <+15>:    callq  0x400664 <func()>
   0x0000000000400696 <+20>:    lea    -0x20(%rbp),%rax
   0x000000000040069a <+24>:    mov    %rax,%rdi
   0x000000000040069d <+27>:    callq  0x4006c4 <std::vector<int, std::allocator<int> >::~vector()>
   0x00000000004006a2 <+32>:    mov    $0x0,%eax
   0x00000000004006a7 <+37>:    leaveq 
   0x00000000004006a8 <+38>:    retq   

I to dla obydwu programów tak samo! Jak to możliwe, skoro w jednym wywołaniu to zapamiętujemy?

1

Wyłącz optymalizacje.

0

ok, wyłączę i wtedy popatrzę, co tu jest optymalizowane?

Proszę jeszcze o odpowiedź na 1. pytanie.

Skompilowałem z opcją
-O0
i asm wyglądają tak samo.

0

co tu jest optymalizowane?

Z tego co widzę, kompilator alokuje zmienną vec2 w rejestrze rax, dlatego ten kod wygląda identycznie.

Z tego co pamiętam, to zwracana wartość wędruje na stosie.

afair w przypadku większości platform (w tym x86, x86-64) najczęściej (zawsze?) zwracana wartość znajduje się w rejestrze.

0

Skompilowałem z opcją
-O0
i asm wyglądają tak samo.

Kompilator usunął drugie wywołanie func(), ponieważ 'nic nie robiło'.

  1. Ok, a jeżeli by go nie usunął to co się dzieje ze zwróconą wartością?
  2. Skoro usunął to wywołanie, to dlaczego kod asm. wygląda tak samo jak w pierwszym przypadku?
1
  1. Ok, a jeżeli by go nie usunął to co się dzieje ze zwróconą wartością?

Nic, pozostaje w rejestrze.

  1. Skoro usunął to wywołanie, to dlaczego kod asm. wygląda tak samo jak w pierwszym przypadku?

Mea culpa, źle spojrzałem na ten kod.

0

ok, wyłączyłem optymalizację ( -O0 ) jak kazał @_13th_Dragon i kody assemblerowe nadal się nie różnią.

1

Chciałbym dowiedzieć się jak odbywa się zwracanie wartości?
To zależy od systemu i od kompilatora. Sam standard języka C++ nie narzuca gdzie ma być przechowywana wartość zwracana przez funkcję.
Dobry kompilator z włączoną optymalizacją może ci utworzyć wektor bezpośrednio pod zmienną vec2 bez kopiowania.

I to dla obydwu programów tak samo! Jak to możliwe, skoro w jednym wywołaniu to zapamiętujemy?
Oba programy robią dokładnie to samo: tworzą wektor, a następnie go niszczą.

Nie ma znaczenia że zapisujesz wektor do zmiennej, skoro zaraz jest zamykający }, zmienna wypada z zasięgu i obiekt jest niszczony. Czyli dokładnie tak samo jak w przypadku gdy nie zapisujesz wyniku do zmiennej.

Tu nie ma znaczenia optymalizacja, po prostu oba programy są równoważne.

0

Tu nie ma znaczenia optymalizacja, po prostu oba programy są równoważne.

Jednak nie. Teraz, gdy wyłączyłem optymalizację copy ellision kody się różnią :)

unique_ptr<int> increment( unique_ptr<int> i )
{
    ++*i;
    return i;
}

Wg bloga, którego czytam zmienna i jest kopiowana. Ja jednak tego nie widzę. Jak to jest kopiowana?

0

Wywołanie konstruktorów w ASMie wygenerowanym masz, prawda?

tak, mam;

Nie, ponieważ w C++ instrukcja object x = ... nie jest przypisaniem do obiektu, tylko utworzeniem obiektu

hmm, czyli jeżeli mam utworzony jakiś już obiekt, np. obiekt a.
to taka operacja:
a =b, gdzie b jest obiektem tego samego typu co powoduje? Z tego co napisałeś, to rozumiem, że odbywa się konstrukcja nowego obiektu na podstawie wartości w b.
Ale dotychczas byłem w przekonaniu, że w takiej sytuacji jest wywoływany konstruktor kopiujący. Jak to w końcu jest?

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