ページ 11

関数の返値の有効範囲について

Posted: 2011年11月09日(水) 21:14
by MoNoQLoREATOR
関数の返り値の有効範囲はどこまでなのでしょうか?

まず、この疑問は次の仮定が誤っていないことを前提としています。
仮定:
ポインタや参照ではなく実体を返す関数が返値を返すと、その分のメモリ領域が確保され、一旦そこにデータが保存される

単純に考えると、 } まででしょうか?
それとも、その行の終わりまで来ると消滅してしまうのでしょうか。
はたまた、それを関数の引数に渡した場合は・・・?


ご教授よろしくお願いいたします。

Re: 関数の返値の有効範囲について

Posted: 2011年11月09日(水) 22:11
by box
MoNoQLoREATOR さんが書きました: 単純に考えると、 } まででしょうか?
どういうコードを想定されていますか?
MoNoQLoREATOR さんが書きました: それとも、その行の終わりまで来ると消滅してしまうのでしょうか。
どういうコードを想定されていますか?
MoNoQLoREATOR さんが書きました: はたまた、それを関数の引数に渡した場合は・・・?
どういうコードを想定されていますか?

Re: 関数の返値の有効範囲について

Posted: 2011年11月09日(水) 22:20
by beatle
その文の終わりまで、だったと思います。

Re: 関数の返値の有効範囲について

Posted: 2011年11月09日(水) 22:38
by box
beatle さんが書きました:その文の終わりまで、だったと思います。
具体例を書いてみていただけないでしょうか。
「その文」というのが何を指すのか、今ひとつピンと来ないものでして。

Re: 関数の返値の有効範囲について

Posted: 2011年11月09日(水) 23:02
by ISLe
『一時オブジェクト』を調べてみてください。

一時オブジェクトの生存期間は完結式の終わりまでです。
いくつか例外がありますが関数の戻り値はそこに含まれません。

Re: 関数の返値の有効範囲について

Posted: 2011年11月09日(水) 23:39
by MoNoQLoREATOR

コード:

#include <string>

string getstr(){
	string output;
	return output;
}

int main(){
	const char *str = getstr().c_str();
	printf(str);
}
このようなコードを想定していたのですが、「一時オブジェクト」で検索してみた結果これは不正アクセスになります・・・よね?
string型で拾って内容をコピーさせるしかなさそうですね。

ありがとうございました。

Re: 関数の返値の有効範囲について

Posted: 2011年11月10日(木) 00:29
by GRAM
仮にstringで拾ったとしても、文字列の内容がコピーされることはないのではないかと思います。
string内部には普通参照カウントがありますので、(そして一時オブジェクトが破棄される前に変更されることもないので)
コピーは浅く行われると予想できます。(予想ですが・・・)
ということでオーバーヘッドは大したことないのではないかと。

追記:
確かにこの場合はNRVOが適応されますね。失礼しました。
自分の話は仮に関数がもっと複雑で、複数のreturn文で異なる名前のインスタンスを返したとしてもと受け取ってください・・・。

Re: 関数の返値の有効範囲について

Posted: 2011年11月10日(木) 01:19
by tk-xleader
「NRVO」や「戻り値最適化」あたりで検索してもらえればより分かりやすい情報が得られると思いますが…
getstr 関数の戻り値はどうせ捨てられる値なので、コピーするよりもムーブしたほうが無駄がありません。C++03でも、この最適化は行われます。
ですから、コピーのコストについては、そこまで問題ではないかと思います。

Re: 関数の返値の有効範囲について

Posted: 2011年11月10日(木) 09:21
by beatle
GRAM さんが書きました:仮にstringで拾ったとしても、文字列の内容がコピーされることはないのではないかと思います。
string内部には普通参照カウントがありますので、(そして一時オブジェクトが破棄される前に変更されることもないので)
コピーは浅く行われると予想できます。(予想ですが・・・)
ということでオーバーヘッドは大したことないのではないかと。
C++11ではstd::basic_stringを参照カウントで実装するのは禁止(というより実質的に不可能)になりました。

Re: 関数の返値の有効範囲について

Posted: 2011年11月10日(木) 09:59
by beatle
box さんが書きました:
beatle さんが書きました:その文の終わりまで、だったと思います。
具体例を書いてみていただけないでしょうか。
「その文」というのが何を指すのか、今ひとつピンと来ないものでして。
僕も少し勘違いしていました。ISLeさんのいうとおり、完結式(full-expression)の終わりまで、のようですね。
ちなみに、「その文」というのは、関数呼び出しを含む文、という意味で使いました。

以下、規格などを調べつつ書いてみました。

コード:

const char* str;
str = getstr().c_str(); // 式1;
printf(str);
式1は他の式の部分式ではないため完結式です。
したがって、strへの代入が終了した時点で完結式が終わり、getstr()の戻り値(一時オブジェクト)のデストラクタが呼ばれます。
もちろんprintf(str)は不正なアクセスです。

一方で

コード:

const char* str;
str = getstr().c_str(), printf(str); // 式2;
の場合、式2は「式3, 式4」という形になっています。
一時オブジェクトを生成する式3は式2の部分式ですから完結式ではなく、式2が完結式です。
カンマ演算子で繋がれた式は左から右に評価されますから、式4が終了すれば式2が終了します。
したがって、式4、つまりprintf(str)を実行後、getstr()の戻り値(一時オブジェクト)のデストラクタが呼ばれます。
printf(str)は不正なアクセスにはなりません。