not an lvalue このエントリーを含むはてなブックマーク このエントリーをブックマークした人数

会社で相談を受けたのでメモ。以下のようなコードを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

Posted by iwadon ( 2009-05-07 13:03:00 GMT ) | カテゴリ | タグ , | トラックバックなし | コメントなし

コメント

トラックバック

トラックバックリンク:
http://moonrock.jp:23000/trackbacks?article_id=569

(leave url/email »)

   前のコメント