読者です 読者をやめる 読者になる 読者になる

0x90

一回休み

C++わからない(´;ω;`)

共同研究者氏に遠慮してPythonを全部C++で書き直してるんですが、

A func() {
  A hoge;
  return hoge;
}

みたいなコードがあった時に、このhogeはどう渡されるのかとか、受ける側は何で受ければいいのかがわかんないので適当にコードを書いてdisasしてみました。

C++弱者ですたすけて

(ていうか本質的にはCで構造体返してるのと同じなので、そこら辺がわかってないC弱者です)

サンプルコード

class A {
  public:
    char hoge[0x100];
};

A testA() {
  A hoge;
  hoge.hoge[0] = 'a';
  return hoge;
}

A testA2() {
  A hoge = testA();
  hoge.hoge[1] = 'b';
  return hoge;
}

int testA3(A hoge) {
  char* aa = hoge.hoge;
  aa[3] = 'c';
  return 0;
}

void getA() {
  A test = testA();
  A test2 = testA2();
  int test3 = testA3(testA());
  int test4 = testA3(test);
}

int main(){return 0;}
$ g++ test.cc
$ objdump -d -M intel a.out | c++filt

ダンプ結果(の必要なとこ)

0000000000400566 <testA()>:
  400566:       55                      push   rbp
  400567:       48 89 e5                mov    rbp,rsp
  40056a:       48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
  40056e:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  400572:       c6 00 61                mov    BYTE PTR [rax],0x61
  400575:       90                      nop
  400576:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  40057a:       5d                      pop    rbp
  40057b:       c3                      ret    

000000000040057c <testA2()>:
  40057c:       55                      push   rbp
  40057d:       48 89 e5                mov    rbp,rsp
  400580:       48 83 ec 08             sub    rsp,0x8
  400584:       48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
  400588:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  40058c:       48 89 c7                mov    rdi,rax
  40058f:       e8 d2 ff ff ff          call   400566 <testA()>
  400594:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  400598:       c6 40 01 62             mov    BYTE PTR [rax+0x1],0x62
  40059c:       90                      nop
  40059d:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  4005a1:       c9                      leave  
  4005a2:       c3                      ret    

00000000004005a3 <testA3(A)>:
  4005a3:       55                      push   rbp
  4005a4:       48 89 e5                mov    rbp,rsp
  4005a7:       48 8d 45 10             lea    rax,[rbp+0x10]
  4005ab:       48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
  4005af:       48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  4005b3:       48 83 c0 03             add    rax,0x3
  4005b7:       c6 00 63                mov    BYTE PTR [rax],0x63
  4005ba:       b8 00 00 00 00          mov    eax,0x0
  4005bf:       5d                      pop    rbp
  4005c0:       c3                      ret    

00000000004005c1 <getA()>:
  4005c1:       55                      push   rbp
  4005c2:       48 89 e5                mov    rbp,rsp
  4005c5:       48 81 ec 10 03 00 00    sub    rsp,0x310
  4005cc:       48 8d 85 f0 fd ff ff    lea    rax,[rbp-0x210]
  4005d3:       48 89 c7                mov    rdi,rax
  4005d6:       e8 8b ff ff ff          call   400566 <testA()>
  4005db:       48 8d 85 f0 fc ff ff    lea    rax,[rbp-0x310]
  4005e2:       48 89 c7                mov    rdi,rax
  4005e5:       e8 92 ff ff ff          call   40057c <testA2()>
  4005ea:       48 8d 85 f0 fe ff ff    lea    rax,[rbp-0x110]
  4005f1:       48 89 c7                mov    rdi,rax
  4005f4:       e8 6d ff ff ff          call   400566 <testA()>
  4005f9:       48 81 ec 00 01 00 00    sub    rsp,0x100
  400600:       48 89 e0                mov    rax,rsp
  400603:       48 89 c7                mov    rdi,rax
  400606:       48 8d 85 f0 fe ff ff    lea    rax,[rbp-0x110]
  40060d:       ba 20 00 00 00          mov    edx,0x20
  400612:       48 89 c6                mov    rsi,rax
  400615:       48 89 d1                mov    rcx,rdx
  400618:       f3 48 a5                rep movs QWORD PTR es:[rdi],QWORD PTR ds:[rsi]
  40061b:       e8 83 ff ff ff          call   4005a3 <testA3(A)>
  400620:       48 81 c4 00 01 00 00    add    rsp,0x100
  400627:       89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  40062a:       48 81 ec 00 01 00 00    sub    rsp,0x100
  400631:       48 89 e0                mov    rax,rsp
  400634:       48 89 c7                mov    rdi,rax
  400637:       48 8d 85 f0 fd ff ff    lea    rax,[rbp-0x210]
  40063e:       ba 20 00 00 00          mov    edx,0x20
  400643:       48 89 c6                mov    rsi,rax
  400646:       48 89 d1                mov    rcx,rdx
  400649:       f3 48 a5                rep movs QWORD PTR es:[rdi],QWORD PTR ds:[rsi]
  40064c:       e8 52 ff ff ff          call   4005a3 <testA3(A)>
  400651:       48 81 c4 00 01 00 00    add    rsp,0x100
  400658:       89 45 f8                mov    DWORD PTR [rbp-0x8],eax
  40065b:       90                      nop
  40065c:       c9                      leave  
  40065d:       c3                      ret     

わかったこと

  • 返り値が大きいクラスの場合、呼び出し側のスタックフレームでメモリを確保して、それを引数rdiに詰めている。
    • testAは、次と等価
void testA(A* targ) {
  targ->hoge[0] = 'a';
}
  • testA2の用に、関数内で変数を確保したように見えても、実体は呼び出し元にある。
  • 引数に渡される場合、いったんコピーが必ず発生する。

わかりません

引数で渡すときにコピーが起きないようにしたい。もっと具体的には、

A func() {
  A hoge;
  return hoge;
}

みたいなコードを、std::vectorに突っ込むときに変なコピーが起きないようにしたい

ムリか。。

追記

多分次でいいのかな

vector<A*> vect;
A* aptr = (A*) malloc(sizeof(A));
*aptr = func();