如何在 C++ 中通过引用返回类对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8914509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:18:37  来源:igfitidea点击:

How to return a class object by reference in C++?

c++referencesegmentation-faultreturn-by-reference

提问by user788171

I have a class called Object which stores some data.

我有一个名为 Object 的类,它存储一些数据。

I would like to return it by reference using a function like this:

我想使用这样的函数通过引用返回它:

    Object& return_Object();

Then, in my code, I would call it like this:

然后,在我的代码中,我会这样称呼它:

    Object myObject = return_Object();

I have written code like this and it compiles. However, when I run the code, I consistently get a seg fault. What is the proper way to return a class object by reference?

我已经编写了这样的代码并且它可以编译。但是,当我运行代码时,我始终遇到段错误。通过引用返回类对象的正确方法是什么?

回答by Chowlett

You're probably returning an object that's on the stack. That is, return_Object()probably looks like this:

您可能正在返回堆栈上的对象。也就是说,return_Object()大概是这样的:

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

    return object_to_return;
}

If this is what you're doing, you're out of luck - object_to_returnhas gone out of scope and been destructed at the end of return_Object, so myObjectrefers to a non-existent object. You either need to return by value, or return an Objectdeclared in a wider scope or newed onto the heap.

如果这是您正在做的事情,那么您就不走运了 -object_to_return已经超出范围并在 结束时被破坏return_Object,因此myObject引用了一个不存在的对象。您要么需要按值返回,要么返回一个Object在更广泛范围内声明的或newed 到堆上。

回答by UmNyobe

You can only use

你只能使用

     Object& return_Object();

if the object returned has a greater scope than the function. For example, you can use it if you have a class where it is encapsulated. If you create an object in your function, use pointers. If you want to modify an existing object, pass it as an argument.

如果返回的对象具有比函数更大的范围。例如,如果您有一个封装了它的类,则可以使用它。如果在函数中创建对象,请使用指针。如果要修改现有对象,请将其作为参数传递。

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

回答by spraff

You can only return non-local objects by reference. The destructor may have invalidated some internal pointer, or whatever.

您只能通过引用返回非本地对象。析构函数可能使某些内部指针无效,或者其他什么。

Don't be afraid of returning values -- it's fast!

不要害怕返回值——它很快

回答by Jayhello

I will show you some examples:

我将向您展示一些示例:

First example, do not return local scope object, for example:

第一个例子,不返回局部作用域对象,例如:

const string &dontDoThis(const string &s)
{
    string local = s;
    return local;
}

You can't return localby reference, because localis destroyed at the end of the body of dontDoThis.

您不能通过local引用返回,因为localdontDoThis.

Second example, you can return by reference:

第二个例子,你可以通过引用返回:

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

Here, you can return by reference both s1and s2because they were defined before shorterStringwas called.

在这里,您可以通过引用返回s1s2因为它们是在shorterString调用之前定义的。

Third example:

第三个例子:

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

usage code as below:

使用代码如下:

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

get_valcan return elements of sby reference because sstill exists after the call.

get_val可以s通过引用返回元素,因为s调用后仍然存在。

Fourth example

第四个例子

class Student
{
public:
    string m_name;
    int age;    

    string &getName();
};

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

string& Test(Student &student)
{
    // we can return `m_name` by reference here because `student` still exists after the call
    return stu.m_name;
}

usage example:

用法示例:

Student student;
student.m_name = 'Hyman';
string name = student.getName();
// or
string name2 = Test(student);

Fifth example:

第五个例子:

class String
{
private:
    char *str_;

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

String &String::operator=(const String &str)
{
    if (this == &str)
    {
        return *this;
    }
    delete [] str_;
    int length = strlen(str.str_);
    str_ = new char[length + 1];
    strcpy(str_, str.str_);
    return *this;
}

You could then use the operator=above like this:

然后你可以operator=像这样使用上面的:

String a;
String b;
String c = b = a;

回答by peterh - Reinstate Monica

Well, it is maybe not a really beautiful solution in the code, but it is really beautiful in the interface of your function. And it is also very efficient. It is ideal if the second is more important for you (for example, you are developing a library).

好吧,它在代码中可能不是一个非常漂亮的解决方案,但它在您的函数界面中确实非常漂亮。而且它也非常有效。如果第二个对您更重要(例如,您正在开发一个库),这是理想的。

The trick is this:

诀窍是这样的:

  1. A line A a = b.make();is internally converted to a constructor of A, i.e. as if you had written A a(b.make());.
  2. Now b.make()should result a new class, with a callback function.
  3. This whole thing can be fine handled only by classes, without any template.
  1. 一行A a = b.make();在内部被转换为 A 的构造函数,即就像你写了A a(b.make());.
  2. 现在b.make()应该产生一个带有回调函数的新类。
  3. 这整个事情只能由类处理,没有任何模板。

Here is my minimal example. Check only the main(), as you can see it is simple. The internals aren't.

这是我的最小示例。只检查main(),如您所见,这很简单。内功不是。

From the viewpoint of the speed: the size of a Factory::Mediatorclass is only 2 pointers, which is more that 1 but not more. And this is the only object in the whole thing which is transferred by value.

从速度上看:一个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;
}