如何在不生成副本的情况下使用 getter 和 setter?

How to use getters and setters without generating a copy?

我想知道如何将 getters 和 setters 用于占用大量内存的成员变量。通常我会这样做:

class A
{
private:
  BigObject object;
public:
  BigObject getObject() const
  {
    return object;
  }

  void setObject(const BigObject& object)
  {
    this->object = object;
  }
};

但是我相信这个 getter 和 setter 会复制我不想要的 BigObject。有更好的方法吗?

我想这样做,但我在网上看到这不是一个好主意,因为如果使用不当会导致分段错误:

BigObject& getObject()
{
  return object
}

您可以 return 引用它,而不是 return 成员的副本。这样就不用复制会员了

I thought of doing it this way but i read on the internet that it's not a good idea because it can lead to a segmentation fault if used badly

解决办法就是不要用坏了

返回对成员的引用是相当常见的模式,通常不鼓励这样做。虽然,对于快速复制的类型,在不需要引用成员本身时,return复制通常更好。

有一个解决方案可以避免封装的复制和破坏:使用共享指针,return 来自 getter 的共享指针的副本。但是,这种方法有运行时成本并且需要动态分配,因此它并不适合所有用例。


在setter的情况下,您可以改用移动赋值,这比某些类型的复制赋值更有效。

通常的做法是:

class A
{
public:
  // this method is const
  const& BigObject getObject() const
  {
    return object;
  }

  // this method is not const
  void setObject(const BigObject& object)
  {
    object = object;
  }
private:
  BigObject object;
};

如果您需要获取只读对象 - 完全没问题。否则,请考虑更改架构。

另一种方法是将 std::shared_ptr 和 return 存储为 std::shared_ptrstd::weak_ptr

(如果你不关心这种情况下的封装,意味着 A::object 成员应该可以不受限制地被任何人修改,那么请看 )。

Return 通过 const 引用以避免复制并仍然保持封装(意味着调用者不能错误地修改成员):

const BigObject& getObject() const
{
    return object;
}

如果来电者确实想要一份副本,他们自己可以轻松完成。

如果你想在 getter 用于临时对象时防止悬挂引用(你提到的段错误),你只能 return 一个副本,而 getter 实际上是拜访临时工:

BigObject getObject() const &&
{
    return object;
}

const BigObject& getObject() const &
{
    return object;
}

这将在调用 getObject() 临时文件时 return 一个副本。或者,您可以通过删除特定的重载来完全防止临时调用 getter:

BigObject getObject() const && = delete;

const BigObject& getObject() const &
{
    return object;
}

请记住,这不是一个有保障的安全网。它可以防止一些错误,但不是全部。函数的调用者仍应了解对象的生命周期。

顺便说一句,您还可以提高 setter。现在,无论调用者如何传递参数,它都将始终复制对象。您应该按值取而代之并将其移动到成员中:

void setObject(BigObject object)
{
    this->object = std::move(object);
}

这要求 BigObject 是可移动的。如果不是,那就更糟了。

最佳解决方案:使您的 class 代码完全符合:

struct A
{
  BigObject object;
};

说明 - 避免琐碎的 setter 和 getter。如果您发现自己将这些放入 classes,请直接公开成员并完成它。

永远不要听别人说 "But what if in the future we add non-trivial logic"?我已经看到了很多琐碎的 setter 和 getter,已经存在了几十年,而且从未被不重要的东西所取代。