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

发布于 2024-12-27 17:07:04 字数 275 浏览 2 评论 0原文

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

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

    Object& return_Object();

然后,在我的代码中,我会这样调用它:

    Object myObject = return_Object();

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

I have a class called Object which stores some data.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

鹿港巷口少年归 2025-01-03 17:07:05

您可能返回堆栈上的一个对象。也就是说,return_Object() 可能看起来像这样:

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

    return object_to_return;
}

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

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

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_return has gone out of scope and been destructed at the end of return_Object, so myObject refers to a non-existent object. You either need to return by value, or return an Object declared in a wider scope or newed onto the heap.

画骨成沙 2025-01-03 17:07:05

可以使用

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

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;
         }
   };
瑕疵 2025-01-03 17:07:05

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

不要害怕返回值 - 速度很快

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!

温柔嚣张 2025-01-03 17:07:05

我将向您展示一些示例:

第一个示例,不要返回本地范围对象,例如:

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

您不能通过引用返回 local,因为 local 在最后被销毁dontDoThis 的主体。

第二个示例,您可以通过引用返回:

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

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

第三个例子:

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

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

第四个示例

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

用法示例:

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

第五个示例:

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

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

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

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 local by reference, because local is destroyed at the end of the body of dontDoThis.

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 s1 and s2 because they were defined before shorterString was called.

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_val can return elements of s by reference because s still exists after the call.

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 = 'jack';
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:

String a;
String b;
String c = b = a;
挖鼻大婶 2025-01-03 17:07:05

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

技巧是这样的:

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

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.

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

From the viewpoint of the speed: the size of a Factory::Mediator class 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.

#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;
}
葵雨 2025-01-03 17:07:05

返回启动的对象并不是一个好的做法,因为它确实超出了范围。在极少数情况下,这是所需的选项。如果该类是引用计数智能指针或其他智能指针,则实际上可以完成此操作。
引用计数智能指针的引用计数如何工作?

It isn't really good practice to return an initiated object as it does go out of scope. There are rare instances that this is the desired option. It actually can be done if the class is a referencing counting smart pointer or some other smart pointer.
How does a reference-counting smart pointer's reference counting work?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文