会社で相談を受けたのでメモ。以下のようなコードをCodeWarriorでコンパイルすると”not an lvalue”と警告される。
struct A
{
int v[100];
};
A foo()
{
A a = {1, 2};
return a;
}
int bar(A *a)
{
return a->v[0] + a->v[1];
}
int main()
{
return bar(&foo());
}
一時的なオブジェクトのアドレスを取ろうとするのがまずいのかな。ちなみにg++だと”taking address of temporary”という警告になる。こちらの方がわかりやすいかな。
以下のように修正するとコピーが発生するので、渡すものが大きいほど時間がかかる。
struct A
{
int v[100];
};
A foo()
{
A a = {1, 2};
return a;
}
int bar(A a)
{
return a.v[0] + a.v[1];
}
int main()
{
return bar(foo());
}
そこで、参照で渡すと良いようだ。実際ポインタを使ったときと出力コードが同じなのに、こちらは警告が出ない。まあNULLを渡すことが無い限り参照で置き換え可能だよね。
struct A
{
int v[100];
};
A foo()
{
A a = {1, 2};
return a;
}
int bar(const A &a)
{
return a.v[0] + a.v[1];
}
int main()
{
return bar(foo());
}
出力コードの差分はこんな感じ。関数のラベル名が違うだけ。
--- a0.s 2009-05-07 20:48:01.296495800 +0900 +++ a2.s 2009-05-07 20:48:49.155870800 +0900 @@ -1,4 +1,4 @@ - .file "a0.cpp" + .file "a2.cpp" .data .align 4 LC0: @@ -29,9 +29,9 @@ ret $4 .align 2 .p2align 4,,15 -.globl __Z3barP1A - .def __Z3barP1A; .scl 2; .type 32; .endef -__Z3barP1A: +.globl __Z3barRK1A + .def __Z3barRK1A; .scl 2; .type 32; .endef +__Z3barRK1A: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx @@ -59,7 +59,7 @@ call __Z3foov subl $4, %esp movl %ebx, (%esp) - call __Z3barP1A + call __Z3barRK1A movl -4(%ebp), %ebx leave ret


コメント
コメントを書く