web-dev-qa-db-ja.com

C ++で参照によってクラスオブジェクトを返す方法は?

データを保存するObjectというクラスがあります。

次のような関数を使用して、参照で返したいと思います。

    Object& return_Object();

次に、私のコードでは、次のように呼び出します。

    Object myObject = return_Object();

このようなコードを記述し、コンパイルします。ただし、コードを実行すると、一貫してセグフォールトが発生します。参照によってクラスオブジェクトを返す適切な方法は何ですか?

32
user788171

おそらくスタック上にあるオブジェクトを返しているでしょう。つまり、return_Object()はおそらく次のようになります。

Object& return_Object()
{
    Object object_to_return;
    // ... do stuff ...

    return object_to_return;
}

これがあなたがしていることなら、あなたは運が悪い-object_to_returnは範囲外になり、return_Objectの終わりに破壊されたので、myObjectは非-既存のオブジェクト。値で返すか、より広いスコープで宣言されたObjectを返すか、ヒープにnewedを返す必要があります。

46
Chowlett

使用できるのは

     Object& return_Object();

返されるオブジェクトのスコープが関数よりも大きい場合。たとえば、カプセル化されたクラスがある場合に使用できます。関数でオブジェクトを作成する場合は、ポインターを使用します。既存のオブジェクトを変更する場合は、引数として渡します。

  class  MyClass{
      private:
        Object myObj;

      public:
         Object& return_Object() {
            return myObj;
         }

         Object* return_created_Object() {
            return new Object();
         }

         bool modify_Object( Object& obj) {
            //  obj = myObj; return true; both possible
            return obj.modifySomething() == true;
         }
   };
21
UmNyobe

参照によってローカル以外のオブジェクトのみを返すことができます。デストラクタは、内部ポインタなどを無効にしている可能性があります。

値を返すことを恐れないでください- 高速です

15
spraff

まあ、それはコードでは本当に美しい解決策ではないかもしれませんが、関数のインターフェースでは本当に美しいです。また、非常に効率的です。 2番目の方がより重要な場合(たとえば、ライブラリを開発している場合)に理想的です。

トリックはこれです:

  1. A a = b.make();は、Aのコンストラクターに内部的に変換されます。つまり、A a(b.make());を記述したかのように変換されます。
  2. これで、b.make()は、コールバック関数を含む新しいクラスになります。
  3. この全体は、テンプレートを使用せずにクラスでのみ適切に処理できます。

これが私の最小限の例です。わかりやすいように、main()のみをチェックしてください。内部はそうではありません。

速度の観点から:Factory::Mediatorクラスは2ポインターのみであり、1以上ですが、それ以上ではありません。そして、これは価値によって転送される全体の中で唯一のオブジェクトです。

#include <stdio.h>

class Factory {
  public:
    class Mediator;

    class Result {
      public:
        Result() {
          printf ("Factory::Result::Result()\n");
        };

        Result(Mediator fm) {
          printf ("Factory::Result::Result(Mediator)\n");
          fm.call(this);
        };
    };

    typedef void (*MakeMethod)(Factory* factory, Result* result);

    class Mediator {
      private:
        Factory* factory;
        MakeMethod makeMethod;

      public:
        Mediator(Factory* factory, MakeMethod makeMethod) {
          printf ("Factory::Mediator::Mediator(Factory*, MakeMethod)\n");
          this->factory = factory;
          this->makeMethod = makeMethod;
        };

        void call(Result* result) {
          printf ("Factory::Mediator::call(Result*)\n");
          (*makeMethod)(factory, result);
        };
    };
};

class A;

class B : private Factory {
  private:
    int v;

  public:
    B(int v) {
      printf ("B::B()\n");
      this->v = v;
    };

    int getV() const {
      printf ("B::getV()\n");
      return v;
    };

    static void makeCb(Factory* f, Factory::Result* a);

    Factory::Mediator make() {
      printf ("Factory::Mediator B::make()\n");
      return Factory::Mediator(static_cast<Factory*>(this), &B::makeCb);
    };
};

class A : private Factory::Result {
  friend class B;

  private:
    int v;

  public:
    A() {
      printf ("A::A()\n");
      v = 0;
    };

    A(Factory::Mediator fm) : Factory::Result(fm) {
      printf ("A::A(Factory::Mediator)\n");
    };

    int getV() const {
      printf ("A::getV()\n");
      return v;
    };

    void setV(int v) {
      printf ("A::setV(%i)\n", v);
      this->v = v;
    };
};

void B::makeCb(Factory* f, Factory::Result* r) {
      printf ("B::makeCb(Factory*, Factory::Result*)\n");
      B* b = static_cast<B*>(f);
      A* a = static_cast<A*>(r);
      a->setV(b->getV()+1);
    };

int main(int argc, char **argv) {
  B b(42);
  A a = b.make();
  printf ("a.v = %i\n", a.getV());
  return 0;
}
2
peterh

いくつか例を示します。

最初の例では、ローカルスコープオブジェクトを返しません。次に例を示します。

const string &mainip(const string &s)
{
    string ret=s;

    //  operator ret

    return ret;
}

retは最後に破棄されるため、retを参照で返すことはできません。

2番目の例では、参照によって戻ることができます。

const string &shorterString(const string &s1,const string &s2)
{
    return s1.size()<s2.size()?s1:s2;
}

s1とs2の両方の参照がまだ存在している場合に戻ります。

3番目の例:

char &get_val(string &str,string::size_type ix)
{
    return str[ix];
}

以下の使用コード:

string s("123456");
cout<<s<<endl;
char &ch = get_val(s,0); 
ch ='A';
cout<<s<<endl; // A23456

参照による戻りの後、オブジェクトはまだ存在しているためです。

4番目の例

class Student{
    public:
        string m_name;
        int age;    

        string& getName();
};

string& Student::getName(){  // you can return by reference
    return m_name;
}

// you can return by reference, after this function stu object is still exists
string& Test(Student &stu)
{
    return stu.m_name;
}

使用例:

Student stu;
stu.m_name = 'jack';
string name = stu.getName(); // 
//or 
string name2 = Test(stu);

5番目の例:

class String{
    private:
        char* str_;

    public:
        String& operator=(const String& str);
};

// for example a=b=c usage
String& String::operator =(const String &str)   
{
    if (this == &str)
    {
        return *this;
    }
    delete [] str_;
    int len = strlen(str.str_);
    str_ = new char[len+1];
    strcpy(str_,str.str_);
    return *this;
}
1
Jayhello