- PR -

return文にあるstringについて

1
投稿者投稿内容
beavis
会議室デビュー日: 2008/08/28
投稿数: 3
投稿日時: 2008-09-09 04:48
いつもお世話になっております。

(環境 VS2005を使用VC++の質問)

現在のソースコードに以下のようなセンテンスがあります。

CString sTest(GetColumnName(CommandID1).c_std());

以下メンバ関数
std::string test::GetColumnName(int commandID)
{
switch(commandID)
{
Case '1'
return "なにか1";
Case '2'
return "なにか 2";
}
}

この文ですと、文字列をそのまま返しているため、変数を作って返すとします。

std::string test::GetColumnName(int commandID)
{
std::string s;
switch(commandID)
{
Case '1'
s = "なにか1";
return s;
Case '2'
s = "なにか 2";
return s;
}
}

上記のような状態でコンパイル実行上、とくに問題は起きません。が、どうも腑に落ちません。
実際実行上でも問題はなかったです。ですが、以下が通常やる場合の文字列返しパターンかとも思います。。

void test::GetColumnName(int commandID, std::string& s)
{
switch(commandID)
{
Case '1'
s = "なにか1";
break;
Case '2'
s = "なにか 2";
break;
}
}

実際1番目でも2番目でもできるのですが、1番目がどうも腑に落ちないため質問させていただきました。

感覚としてこれではだめなんじゃないかということなのですが、特にスコープの問題も起きずに実行できました。

これは、どちらでもよいのでしょうか?それとも2番目のやり方が正しい方法なのでしょうか?

知っている上では局所的に変数を作った場合(この場合std::string s)それを返してはいけないはずなのですが、この場合問題は起きませんでした。
それがわかっているため、腑に落ちないのですが。。。

以上初心者レベルかもしれない質問になります。
どうかよろしくお願いします。
Azulean
大ベテラン
会議室デビュー日: 2008/01/04
投稿数: 123
お住まい・勤務地: 大阪府
投稿日時: 2008-09-09 07:38
私の適当な理解で書きます。
正しい知識は言語仕様を見て身につけて下さい。

また、仕様に詳しい方、説明でまずい点があればご指摘をお願いします。

引用:

std::string test::GetColumnName(int commandID)
{
return "なにか1";
}


return文でstd::string("なにか1");が実行され、この内容が返されます。
(コピーコンストラクタが走るかどうかは覚えていません)

引用:

std::string test::GetColumnName(int commandID)
{
std::string s;
s = "なにか1";
return s;
}


return文でstd::stringのコピーコンストラクタが走ります。

引用:

これは、どちらでもよいのでしょうか?それとも2番目のやり方が正しい方法なのでしょうか?


最適化によって差を埋めてくれることもありますが、return s;とした場合に実際にコピーが走るコードが残る可能性もあります。
従って、std::string&の引数で処理した方がコストが少ない可能性があるのかもしれません。

引用:

知っている上では局所的に変数を作った場合(この場合std::string s)それを返してはいけないはずなのですが、この場合問題は起きませんでした。
それがわかっているため、腑に落ちないのですが。。。


よく「だめ」と言われるのは、ローカル変数のポインタを返すことです。

int* Func()
{
int a = 5;
return &a;
}

このような場合、aの位置は関数を抜けた時点で使われなくなり、期待した値にならない可能性があります。
Azulean
大ベテラン
会議室デビュー日: 2008/01/04
投稿数: 123
お住まい・勤務地: 大阪府
投稿日時: 2008-09-09 07:41
あとはcommandIDが想定外の値だった場合の対応ですね。

空文字列を返すのであれば、std::stringが戻り値でも構わないかもしれませんが、成否(true/false)やエラーコード(intとか?)を戻り値として返したい場合は、関数の戻り値を成否やエラーコードの型で、成功時の戻り値を引数でということも考えられます。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2008-09-09 07:47
おはようございます。

引用:

実際1番目でも2番目でもできるのですが、1番目がどうも腑に落ちないため質問させていただきました。
感覚としてこれではだめなんじゃないかということなのですが、特にスコープの問題も起きずに実行できました。



1番目は、いわゆる「(型)変換コンストラクタ」が働き、暗黙の型変換がおこなわれています。
2番目は、ローカル変数を返す際に「コピーコンストラクタ」によって、コピーされています。

私的には…
2番目では、文字列を返すために2度コンストラクタを呼び出さないといけないオーバーヘッドを嫌い
できるだけ避けたいですね。
つまり、1番目のほうがよいと思います。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-09-09 21:40
引用:

beavisさんの書き込み (2008-09-09 04:48) より:
コード:
CString sTest(GetColumnName(CommandID1).c_std());

std::string test::GetColumnName(int commandID)
{
    switch(commandID)
    {
    Case '1'
        return "なにか1";
    Case '2'
        return "なにか 2";
    }
}



そもそも、コンパイルが通らないと思います。

引用:

(環境 VS2005を使用VC++の質問)


VC++8 では、デフォルトで UNICODE 指定です。CString は、「typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;」と、定義されていると思います。このため、Unicode 文字列を期待するようにプリコンパイルされます。std::string とは、文字コードが異なります。

引用:

実際1番目でも2番目でもできるのですが、1番目がどうも腑に落ちないため質問させていただきました。

感覚としてこれではだめなんじゃないかということなのですが、特にスコープの問題も起きずに実行できました。


 「感覚として」ということなので「1番目がどうも腑に落ちない」については突っ込みません。しかし、その後の「特にスコープの問題も起きずに」とのつながりがわかりませんでした。これによって、「1番目って、メソッド内で s を宣言しているコードのこと?」と、混乱しました。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-09-09 22:28
引用:

beavisさんの書き込み (2008-09-09 04:48) より:
上記のような状態でコンパイル実行上、とくに問題は起きません。が、どうも腑に落ちません。


私は C++ はあまり知らないので直接的な回答はできませんが、こういうのはデバッガーでステップ実行させてみると分かりやすいです。コード上ではあらわに見えない暗黙のコンストラクターなども通ることが分かると思います。
1

スキルアップ/キャリアアップ(JOB@IT)