オブジェクトの参照を返す関数の扱い

このQ&Aのポイント
  • オブジェクトの参照を返す関数で、関数内で作成されたオブジェクトは関数終了後に実体がなくなるため、アドレスのような数列が表示されます。
  • 関数でオブジェクトを作成しプログラム本体に渡す際は、オブジェクト自体をコピーしなければ参照で渡すことはできません。
回答を見る
  • ベストアンサー

オブジェクトの参照を返す関数の扱い

オブジェクトの作成と関数との関係を勉強していますが参照の使い方に関して質問させていただきたいと思います。 以下のような簡単なプログラムを作りました。 myclass.cpp myclass.h で記述されたクラスmyclassは整数を一つ持ち、show_value関数でその整数を表示し、say_heyで"hey"という文字を出力するというものです。 このクラスを利用するプログラムとしてmain.cppをつくりました。このなかには2つの関数が使われます。 -オブジェクトをつくりそれをオブジェクトとして返す関数(return_obj)   -オブジェクトをつくりそれの参照を返す関数(return_ref_obj) これらの関数を用いてオブジェクトをつくり、そのオブジェクトを戻り値としてmainのなかでオブジェクトのshow_value関数で保持する整数を表示する、というものです。 myclass.h-------------------------------- class Myclass{ public: int my_int; Myclass(); ~Myclass(); void show_value(); void say_hey(); }; myclass.cpp---------------------------------- #include "myclass.h" #include <iostream> using namespace std; Myclass::Myclass(){}; Myclass::~Myclass(){}; void Myclass::show_value(){ printf("%d\n", my_int); } void Myclass::say_hey(){ printf("hey\n"); } main.cpp------------ #include <iostream> #include "myclass.h" using namespace std; //オブジェクトをつくりそれをオブジェクトとして返す関数(return_obj)   Myclass return_obj(int int_in){ Myclass myobject; myobject.my_int = int_in; //引数をオブジェクトのmy_intに渡す return myobject; } //オブジェクトをつくりそれの参照を返す関数(return_ref_obj) Myclass& return_ref_obj(int int_in2){ Myclass myobject; myobject.my_int = int_in2;   //引数をオブジェクトのmy_intに渡す Myclass& ref_of_myclass = myobject; return ref_of_myclass; } void main(){ Myclass returned_obj = return_obj(1); //関数に1を渡し、1を保持するオブジェクトを作成 returned_obj.show_value(); //整数(1)表示 returned_obj.say_hey(); Myclass& ref_obj = return_ref_obj(2); //関数に2を渡し、2を保持するオブジェクトを作成し参照として受け取る ref_obj.show_value(); //整数(2)表示 ref_obj.say_hey(); } プログラムを実行した出力------------------- 1 hey -858993460 hey このようにオブジェクト自体を返してコピーしたもの(return_obj使用)はshow_valueでただしくオブジェクトに保持された数が表示されますが 参照でオブジェクトを返したもの(return_ref_obj使用)はアドレスのような数列が表示されます。 質問A これはオブジェクトの参照を返す関数(return_ref_obj)でオブジェクトを作成しても、そのオブジェクトが関数の中でのみ実在しており、関数がおわるとその実体がなくなるためではないかと解釈しているのですがそれで正しいでしょうか? 質問B 関数でオブジェクトを作成してそれをプログラム本体に渡すときはreturn_objのようにオブジェクト自体をコピーしなければ参照などで渡すことはできないのでしょうか? クラスと参照自体勉強を始めたばかりで色々と初歩的な間違いもあるとは思いますが、よろしくお願いします

質問者が選んだベストアンサー

  • ベストアンサー
  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

質問A:その理解で正しいです。 質問B:作ったオブジェクトを参照で返すのは止めた方が良いです。 オブジェクトをコピーで返しましょう。 あるいはnewで作ってポインタで返しましょう。 関数内で自動変数を宣言して作ったオブジェクトはその関数を終えると削除されるので、そこへの参照は懸垂参照という不正な状態になります。 newで作成したオブジェクトはdeleteするまで存在するので関数から返せます。このときは参照でなくポインタを返しましょう。参照を返すとdeleteが面倒です。

hydrozoa
質問者

お礼

回答ありがとうございました。 ポインタはなにかと面倒そうなイメージもあり、参照が使えないかと思っていたんですがそうもいかないようですね。 今回のようなオブジェクトの有効な範囲というのは私がプログラミングでいまいち感覚がつかめていなかった部分なのですが、今回の件でとても勉強になりました。

その他の回答 (1)

  • jagd-doga
  • ベストアンサー率31% (14/45)
回答No.2

rinkun さんがおっしゃるとおり、 「関数がおわるとその実体がなくなるため」 という理解で正しいです。 newしてポインタを返すほかには、関数内の自動変数を静的に宣言する方法があります。 シングルトンパターンになるんですかね。 こんな感じです。 class A& method() {   static class A;   return A; } これなら、method() をreturnした後も class Aはなくならないので大丈夫なはずです。 また、呼び出し元でdeleteしなくても済みます。 ただし、複数の呼び出し元で、ひとつのインスタンスを共通して使用することになるので、その点は注意が必要です。 特に、起動後初回の呼び出しで class Aのコンストラクタが処理されるので、初回呼び出し時に複数スレッドから同時にアクセスされると例外が発生することがあります。

hydrozoa
質問者

お礼

具体的なコードありがとうございます。勉強になりました。 new, staticなどは知識としては多少ありましたが、実際に使うのはちょっと躊躇してしまっていました。これからは積極的に使ってみようと思います。

関連するQ&A

  • 整数値を任意のオブジェクトを格納できるスタッククラスに格納する方法

    class ObjStack { private Object[] mBuf; private int mSP; public ObjStack(int size) { mSP = 0; mBuf = new Object[size]; } public int getSize() { return mBuf.length; } public int getNum() { return mSP; } public boolean isFull() { return mSP == mBuf.length; } public boolean isEmpty() { return mSP == 0; } public void push(Object x) { if (!isFull()) { mBuf[mSP++] = x; } } public Object top() { Object obj = null; if (!isEmpty()) { obj = mBuf[mSP-1]; } return obj; } public Object pop() { Object obj = null; if (!isEmpty()) { obj = mBuf[--mSP]; } return obj; } } 上のプログラムは任意のオブジェクトを格納できるスタッククラスです。 int型の値はオブジェクトではないので、このObjyStackクラスに格納することができない。 整数値をこのObjStackクラスに格納する方法を教えて下さい。

    • ベストアンサー
    • Java
  • c# refで渡すようにオブジェクトで渡したい

    こんにちは。c#初心者です。 以下のコードで、 ValueChanging(this, ref Sample, ref value); と、しているところを ValueChanging(this, e)のようにひとつのオブジェクトにまとめて同じ結果にするようなことはできるのでしょうか? わかる方いらっしゃいましたら教えてください。 もし、無理なら無理と言っていただけるとありがたいです。 -------------------------------------------------------- //イベント類 public delegate void ValueChangingHandler(object sender, ref oldValue, ref newValue); public event ValueChangingHandler ValueChanging; //フィールド&プロパティ protected int Sample; public int Value { get { return Sample; } set { ValueChanging(this, ref Sample, ref value); } } --------------------------------------------------------

  • 関数 左辺値 参照 返り値 

    こんにちは。宜しくお願い致します。 > たとえば,下のサンプルプログラムでは関数fが参照を返すようになっているため,この関数fを代入の左辺においた,f(a, n) = 10;のような式が許される. > > #include <iostream> > using namespace std; > > int& f(int* a, int n) > { (2)~ return a[n]; > } > > int main(void) > { > const int n = 5; > int arr[n] = { 1, 2, 3, 4, 5 }; (1)~ f(arr, 3) = 10; > for (int i = 0; i < n; ++i) > cout << arr[i] << endl; > return 0; > } 上のサンプルプログラムで左辺値に参照を返す関数が(1)~あるのですが 動作が分りません。 関数内部の(2)~return a[n];というところで、関数の返り値int&の参照はa[n]という変数になるので、(1)~の結果としてa[n]に10が代入されるのでしょうか?教えてください。

  • コンパイルエラー。間違ってるのは誰?(どこ?)

    Effective C++の「型変換をさせたいなら、メンバでない関数をクラステンプレートの中で定義しよう」という項目に乗っていたコードを実験してみたのですが、コンパイルでエラーが出るようです。 ----- template<typename T> class Rational { T numerator_value; T denominator_value; public: Rational(const T& num=0, const T& den=1) :numerator_value(num), denominator_value(den){} const T numerator(){return numerator_value;} const T denominator(){return denominator_value;} void show() const { std::cout<<"numerator="<<numerator_value<<": denominator="<<denominator_value<<std::endl; } friend const Rational operator*(const Rational& lhs, const Rational& rhs) //←引数がおかしい? { return Rational(lhs.numerator()*rhs.numerator(), lhs.denominator()*rhs.denominator()); } }; int main() { Rational<int> obj1(1,10); Rational<int> obj2; obj2=obj1*10; obj2.show(); return 0; } ----- こういうコードを書いたのですが、friend関数の部分で「'const Rational<T>' から 'Rational<T> &' へ 'this' ポインタを変換できません」等と怒られます。 引数に取る二つの値のどちらもおかしいようで、コンパイルのエラーを出さないようにするためには、constと&を外さないといけないようです。 引数はEffectiveC++の掲載コードをそのまま使っています。 これは、私のコードがおかしいのか、本のコードがおかしいのかどちらでしょうか?

  • 自身の関数オブジェクトを参照するには?

    自身の関数オブジェクトを参照するには? 次のようなコードを書いてみました。(全角空白は半角インデントに置換してください) <p id="Target"><span><span><span><span><span><span>Hello, World!</span></span></span></span></span></span></p> <script type="text/javascript"> (function(){  function Hello(HTMLElement){   var firstChild = HTMLElement.firstChild;   var result;   switch(firstChild.nodeType){    case 1: // Element Node     result = Hello(firstChild); // 再帰呼び出し     break;    case 3: // Text Node     result = firstChild.nodeValue;     break;   }   return result;  }  var text = Hello(document.getElementById('Target'));  alert(text); // Hello, World! })(); </script> 再帰呼び出しの部分で "Hello" の文字列を使わない方法を模索しています。 # この場合、while を使えば再帰呼び出しを使わなくすることも出来ますが、実際のコードはかなり複雑で上手い方法を思いつきませんでした。 # 時間をかければ再帰呼び出しを使わないように修正することも出来るのでしょうが、今はさくっと再帰呼び出しで解決することを望んでいます。 具体的には、 result = this(firstChild); このように呼び出せるのが理想です。 (この場合のthis値は windowオブジェクト を参照するので、上記は期待通りに動作しません) this とオブジェクトを組み合わせる方法も考えましたが、肝心の "Hello" を省略できませんでした。 var obj = {}; obj.Hello = function(){ this.Hello(); }; 何か良い方法はないでしょうか?

  • 単方向リストに適当な値を入れて、逆順に表示するプログラムの仕組みがわかりません。

    以下のプログラムのReverceShowValue関数の仕組みがわかりません。 申し訳ございませんが、ご教授の方、よろしくお願いします。 #if 1 /* リスト構造の実装 * 再帰関数を用いて逆順に表示 */ #include <stdio.h> #include <stdlib.h> typedef struct object{ int value; struct object *next; }OBJ; OBJ* AllocateBlock(int value) { OBJ *block; block = (OBJ*)malloc(sizeof(OBJ)); if(block == NULL){ printf("Allocate Error\n"); exit(1); } block->value = value; block->next = NULL; return block; } void ReverceShowValue(OBJ *p) { if(p != NULL){ ReverceShowValue(p->next); printf("%d\n", p->value); } } void FreeAllocate(OBJ *p_top) { OBJ *temp; while(p_top != NULL){ temp = p_top->next; free(p_top); p_top = temp; } } int main(void) { OBJ *top = NULL; OBJ *temp; int i; for(i = 0;i < 10;i++){ if(top == NULL){ top = AllocateBlock(i); temp = top; } else{ temp->next = AllocateBlock(i); temp = temp->next; } } ReverceShowValue(top); FreeAllocate(top); return 0; } #endif

  • C言語 関数の問題

    C言語(関数の問題)で読み込んだ4つの整数の最大値を求めプログラムで 整数を2つペア比較し、関数の入れ子を用いて最大値を見つけて、表示する。 というプログラムを作成したいのですが #include<stdio.h> int maxof(int a, int b) { if(a > b) return (a); else return (b); } int max4(int a, int b, int c, int d) { max(max(a, b), max(c, d)); } int main(void) { int num1,num2, num3, num4; ------ 整数の読み込み printf("最大値は%dです。", max4(num1, num2, num3, num4)); return(0); } と記述すると、上手くいったのですが これを max関数だけを用いて作成できますでしょうか? 整数の比較は全てmax関数で行いたいです。

  • C# 関数はどこに書くの?

    c#を始めました。 関数はどこに書けばよいのだろうと思い以下の2つのパターンを書きました。どちらも実行するとちゃんと動いています。 どちらの書き方が正しいのでしょうか?よろしくお願いいたします。 パターン1 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { int a=3; int n= tasu(a); MessageBox.Show(n.ToString());   //ここに関数を書く int tasu(int a10) { return a10 - 2; } } } パターン2 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { int a=3; int n= tasu(a); MessageBox.Show(n.ToString()); }   //ここに関数を書く int tasu(int a20) { return a20 -1; } }

  • 参照渡し と ポインタ渡し

    参照渡し と ポインタ渡し はどういう時に使い分けるんですか? VOID型の自作関数内でメインのブール値を書き替えたいんだけど #include <iostream.h> void ref( int &b ) { b = false; } void ptr( int *b ){ ( *b ) = true; } main(){  bool b = true;  ref( b );  cout << b;  ptr( &b );  cout << b; } だとコンパイルエラーでした。 うまくいくソースを教えてください。

  • 参照型のオフセット取得

    C++でリフレクションを実装するため、全メンバー変数のオフセット をoffsetofで取得し、メンバ変数名とオフセットをstd::mapに登録 しようとしています。 ここで質問なのですが、参照型に対してoffsetofを取得しようとすると アクセス違反で落ちてしまいます。原因を調べてみると、クラスの オブジェクトがobj、メンバ変数が参照型refだとすると、&obj.refは ref変数のアドレスを返すのでは無く、refが指している変数のアドレス を返してくるのが原因でした。 長くなりましたが、ref変数のアドレスを取得する方法、またはオフセット を取得する方法は無いのでしょうか?これが出来ないと、参照型については未サポートにするしか無くなってしまいます><

専門家に質問してみよう