Как вернуть объект класса по ссылке в C ++? - PullRequest
32 голосов
/ 18 января 2012

У меня есть класс Object, который хранит некоторые данные.

Я бы хотел вернуть его по ссылке, используя такую ​​функцию:

    Object& return_Object();

Тогда в моем коде я бы назвал это так:

    Object myObject = return_Object();

Я написал такой код, и он компилируется. Однако, когда я запускаю код, я последовательно получаю ошибку сегмента. Как правильно вернуть объект класса по ссылке?

Ответы [ 5 ]

45 голосов
/ 18 января 2012

Вы, вероятно, возвращаете объект, который находится в стеке. То есть return_Object(), вероятно, выглядит так:

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

    return object_to_return;
}

Если это то, что вы делаете, вам не повезло - object_to_return вышел из области видимости и был уничтожен в конце return_Object, поэтому myObject относится к несуществующему объекту. Вам нужно либо вернуть по значению, либо вернуть Object, объявленный в более широкой области видимости, или new ed в кучу.

21 голосов
/ 18 января 2012

Вы можете использовать только

     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;
         }
   };
15 голосов
/ 18 января 2012

Вы можете возвращать нелокальные объекты только по ссылке.Деструктор мог сделать недействительным какой-то внутренний указатель или что-то еще.

Не бойтесь возвращать значения - это быстро !

2 голосов
/ 26 июня 2016

Ну, это может быть не очень красивое решение в коде, но оно действительно красивое в интерфейсе вашей функции.И это тоже очень эффективно.Идеально, если второе более важно для вас (например, вы разрабатываете библиотеку).

Хитрость заключается в следующем:

  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;
}
1 голос
/ 30 мая 2018

Я покажу вам несколько примеров:

Первый пример, не возвращайте объект локальной области, например:

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

    //  operator ret

    return ret;
}

вы не можете вернуть ret по ссылке, потому что ret isуничтожен в конце.

Второй пример, вы можете вернуться по ссылке:

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

вы можете вернуться по ссылке, поскольку s1 и s2 все еще существуют.

Третийпример:

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

, поскольку после возврата по ссылке объект все еще существует;

Четвертый пример

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);

Пятый пример:

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;
}
...