人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

C++得意な方へ質問なのですが、何故 非constな参照を一時オブジェクトで初期化できないのでしょうか?

class A
{
public:
A() {}
~A() {}
};

void test(A& a)
{
a.method();
}

void test_main()
{
test(A()); // <- この行
}

ここで、test(A())の行で、
initial value of reference to non-const must be an lvalue
というエラーが出てしまいます。const参照ならば、当然OKですが このようになっている理由が知りたいです。



●質問者: suzume_oyado
●カテゴリ:コンピュータ
✍キーワード:C++ Class const test void
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● しおり
●27ポイント

非const参照は、変更したオブジェクトを呼び出し側に返す事を期待しているはずなので、一時オブジェクトを渡しているのはバグだろうと気を利かせているだけだと思います。

◎質問者からの返答

期待はずれにならないようにという配慮ですね? 優しい…。


2 ● ymiz777
●27ポイント

C++の関数は、オブジェクトのリファレンスを戻り値にすることがありますが、当然、その関数の引数として与えられたオブジェクトのリファレンスを戻すこともできるので、引数に一時オブジェクトを指定できしまうと、戻り値を受ける側が、何もないオブジェクトを指し示してしまうということを避けるための措置ではないかと思います。

ただ、このように考えると、逆に、const参照であれば、認められる方が不思議になってしまうかもしれませんが、const参照だけは、なぜか、一時オブジェクトの生存期間を、参照がなくなるまで、拘束できるという、一見、難しいルールがあります。

ご質問の内容に、近しい内容の説明をしていたページが、以下にありました。

http://www.sun-inet.or.jp/~yaneurao/intensive/cppmaniax/chap0001...

この中で、以下のlist-5を参照してもらうと、このルールの意味が理解できるのではないかと思います。

int& i = int(1); // error

const int& i = int(1); // ok

このokまで、errorにされては、たまりませんね。

--------

ちなみに、ご質問の文中にあったコードを、Visual C++ 2005で、コンパイルしようとすると、ノーエラーで、コンパイルできてしまいます。

ただ、以下のようなコードに変形をすると、確かに、test_main()関数の戻り値は、Aのデストラクタが呼び出された後に、returnをしていて、test_main()関数を呼び出した側では、無効なオブジェクトの参照を受けてしまっているようです。


class A

{

public:

A() {}

~A() {}

void method(void) {}

};

A& test(A& a)

{

a.method();

return a;

}


A& test_main()

{

return test(A()); // <- この行

}

◎質問者からの返答

気を利かせた説が有力…?


3 ● mj99
●26ポイント

こうゆう例の方がわかりやすいかも。

----

void test(int& a)

{

a = a + 1;

}

void test_main()

{

test(10);

}

----

意味のないコードですよね。

コンパイラが気を利かせている説有力

(ちなみに上記のコードは、Microsoft C,Borland Cではエラーならず、警告になりました)

◎質問者からの返答

コード的に意味の無いコードは他にもいくらでもあるのに、この件についてだけ、エラーになるコンパイラがある理由がわかりません。何か、論理的に説明が付くものがあると思うのです。


4 ● ccv
●10ポイント

http://d.hatena.ne.jp/asin/475611895X

一時オブジェクトでの初期化を認めることによって発生するリスクについて『プログラミング言語C++第3版』に記載されています。

$7.2 引数渡し (P.189)

////////////////////////////////////////

void update(float& i);

void g(double d, float r)

{

update(2.0f);// エラー:定数引数

update(r);// rのリファレンスを渡す

update(d);// エラー:型変換が必要

}

これらの呼び出しが認められていたら、update()はすぐに削除されてしまう一時変数を何も言わずに更新していただろう。このようなことが起きたら、プログラマをびっくりさせるはずである。

////////////////////////////////////////

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ