文字列の寿命について – プログラミング – Home

通知
すべてクリア

[解決済] 文字列の寿命について


enokobo
 enokobo
(@enokobo)
ゲスト
結合: 20年前
投稿: 5
Topic starter  

はじめまして, enokoboと申します。

早速ですが, C++の文字列の寿命について質問させて頂きます。
例えば, 次のような関数があった場合,

char *GetString()
{
return Test;
}

std::cout << GetString();
などの呼び出し側で文字列を出力できてしまうのですが,
TestはGetString()関数を出るときに破棄されないのでしょうか?

何かご存知の方がいらっしゃいましたら, ご教授願います。


引用未解決
トピックタグ
RAPT
 RAPT
(@RAPT)
ゲスト
結合: 22年前
投稿: 310
 

文が終了するまでは、一時オブジェクトが作成されているから。
関数呼び出し元で、文が終わった時に一時オブジェクトは無効になる。


返信引用
enokobo
 enokobo
(@enokobo)
ゲスト
結合: 20年前
投稿: 5
Topic starter  

RAPTさん, ご回答ありがとうございます。

すみません, まだちょっと理解できないのですが,

① 文字列の場合,

#include <iostream>

void ShowString(char *pString)
{
std::cout << pString;
}

char *GetString()
{
return test;
}

と定義されていたときに
ShowString(GetString());
という呼び出しは有効になります。
しかし,

② クラス オブジェクトの場合,

#include <iostream>

class CMyClass
{
public:
int m_iValue;
CMyClass(int iValue)
{
m_iValue = iValue;
}
};

void ShowMyClass(CMyClass *pMyClass)
{
std::cout << pMyClass->m_iValue;
}

CMyClass *GetMyClass()
{
return &CMyClass(10);
}

と定義されていたときに
ShowMyClass(GetMyClass());
という呼び出しは無効になってしまいます。

文字列のときと何が違うのでしょうか?

初歩的な質問で申し訳ありませんが, よろしくお願い致します。


返信引用
瀬戸っぷ
 瀬戸っぷ
(@瀬戸っぷ)
ゲスト
結合: 22年前
投稿: 160
 

> return test;

こちらは、「文字列リラテルのアドレス」を返しています。
文字列リラテルなので、メモリ上に固定的に割り当てられた領域に確保されています。

> return &CMyClass(10);

こちらは、一時的に作られたクラスのアドレスを返している…かと。
(C++勉強中故ちょっと自信なし)
こちらはたいていスタック上に作成されるので関数から戻った際に無効になります。
デストラクタが片づけている…かな?
一時オブジェクトが作成されてソレが返される場合もあるようですが。


返信引用
...
 ...
(@...)
ゲスト
結合: 22年前
投稿: 113
 

>char *GetString()
>{
> return test;
>}
char *GetString()
{
char* c = test ;
return c;
}
どうなると思いますか?


返信引用
REE
 REE
(@REE)
ゲスト
結合: 23年前
投稿: 240
 

>char *GetString()
>{
> return Test;
>}
>
>std::cout << GetString();
>などの呼び出し側で文字列を出力できてしまうのですが,

これはそう出来る実装が多いだけで、保証はされていないとお考え下さい。
この例では一時オブジェクトも作られません。

ということで、クラスオブジェクトの場合でも同様に保証はされません。


返信引用
enokobo
 enokobo
(@enokobo)
ゲスト
結合: 20年前
投稿: 5
Topic starter  

瀬戸っぷさん, ...さん(お名前でよろしいのでしょうか?), ありがとうございます。

> こちらは、「文字列リラテルのアドレス」を返しています。
> 文字列リラテルなので、メモリ上に固定的に割り当てられた領域に確保されていま
す。

なるほど, 文字列リテラルは静的なデータ領域に確保されるんですね。
だから, GetString()関数を出た後でも残っているんですね。

> char *GetString()
> {
> char* c = test ;
> return c;
> }
> どうなると思いますか?

これも, 瀬戸っぷさんがおっしゃっているように,
静的なデータ領域のアドレスですから, 問題ありませんね。
# ちょっと自身がなかったので試してみました。

②のクラス オブジェクトの場合ですが,
呼び出し元を
std::cout << GetMyClass()->m_iValue;
としたときには正確な読み出しができました。

ローカル変数の寿命は関数内だとすると,
辻褄が合っていないと思います。

スタックが破棄されるタイミングなどは,
コンパイラによってまちまちなのでしょうか?

それとも, このようなローカル変数のアクセスは正当なのでしょうか?


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 22年前
投稿: 320
 

> (1) 文字列の場合,
> char *GetString()
> {
> return test;
> }

char *でなくconst char *とした場合,これは,

const char *GetString()
{
static const char [] __test = test;
return __test;
}
と同等です。
#文字列リテラルからchar *への変換は特殊例なので脇にのけておきます。

> (2) クラス オブジェクトの場合,
> CMyClass *GetMyClass()
> {
> return &CMyClass(10);
> }

これは,
CMyClass *GetMyClass()
{
{ // テンポラリオブジェクトのスコープ
CMyClass __temp(10);
return &__temp;
}
}
と同等です。

前者はstaticオブジェクトへのポインタを返しているのに対して,
後者はテンポラリオブジェクトへのポインタを返しています。
テンポラリオブジェクトは,その式が終了した時点で破棄されますから,
テンポラリオブジェクトへのポインタは無効なポインタになります。

> >char *GetString()
> >{
> > return Test;
> >}
> >std::cout << GetString();
> >などの呼び出し側で文字列を出力できてしまうのですが,
> これはそう出来る実装が多いだけで、保証はされていないとお考え下さい。

こっちは保障されているはずですが。
何が保障されていないかが気になります。

書いている間に返信があったので追加しておきます。

> (2)のクラス オブジェクトの場合ですが,
> 呼び出し元を
> std::cout << GetMyClass()->m_iValue;
> としたときには正確な読み出しができました。

これは「たまたま」です。
CMyClassにデストラクタを書いて,タイミングを調べてみると良いでしょう。

> ローカル変数の寿命は関数内だとすると,
> 辻褄が合っていないと思います。
> スタックが破棄されるタイミングなどは,
> コンパイラによってまちまちなのでしょうか?

テンポラリオブジェクトがどのタイミングで破棄されるかは,完全に決まっています。
次の二種類を除き,テンポラリオブジェクトが生成された完全式の評価が終了した時点で
破棄されます。
・テンポラリオブジェクトが初期化に使われている場合
・constリファレンスに束縛されている場合

> それとも, このようなローカル変数のアクセスは正当なのでしょうか?

不正です。
動いたのは,先にも書いたとおり「たまたま」です。


返信引用
enokobo
 enokobo
(@enokobo)
ゲスト
結合: 20年前
投稿: 5
Topic starter  

REEさん, すみません。書き込み中でした。

> これはそう出来る実装が多いだけで、保証はされていないとお考え下さい。
> この例では一時オブジェクトも作られません。

> ということで、クラスオブジェクトの場合でも同様に保証はされません。

つまり,

・文字列リテラルを静的なデータ領域に保持する
・スタックを破棄するタイミング

これらは, コンパイラ次第ということですか?


返信引用
REE
 REE
(@REE)
ゲスト
結合: 23年前
投稿: 240
 

> >char *GetString()
> >{
> > return Test;
> >}
> >std::cout << GetString();
> >などの呼び出し側で文字列を出力できてしまうのですが,
> これはそう出来る実装が多いだけで、保証はされていないとお考え下さい。

これについては、撤回します。
よく考えたら、保証されていないと困りますね。

余計な混乱を招いて申し訳ありませんでした。


返信引用
enokobo
 enokobo
(@enokobo)
ゲスト
結合: 20年前
投稿: 5
Topic starter  

YuOさん, またそれ以前にご回答頂いた皆様, ありがとうございました。
お蔭様でようやく理解することができました。

どうも私の中で,
・文字列リテラルの寿命
・テンポラリ オブジェクトの寿命
・ローカル オブジェクトの寿命
を混同していました。

今後ともよろしくお願い致します。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました