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

时间:2019-08-15 19:24:33

标签: c++ getter-setter

我想知道如何为需要大量内存的成员变量使用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
}

4 个答案:

答案 0 :(得分:6)

(如果您在这种情况下不关心封装,则意味着A::object成员可以不受任何限制地被任何人修改,然后查看SergeyA's answer)。

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

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

如果呼叫者确实想要复制,他们可以自己轻松进行复制。

如果要防止在临时使用getter时悬挂引用(提到的段错误),则只能在实际在临时上调用getter时返回副本:

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

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

在临时调用getObject()时,它将返回一个副本。另外,您可以通过删除特定的重载完全阻止临时调用getter:

BigObject getObject() const && = delete;

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

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

您还可以改善二传手。现在,无论调用者如何传递参数,它都将始终复制对象。您应该改为按值取值并将其移入成员:

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

这需要BigObject可以移动。如果不是这样,那将比以前更糟。

答案 1 :(得分:4)

最佳解决方案:准确地为您的类编写代码:

struct A
{
  BigObject object;
};

说明-避免琐碎的设置者和获取者。如果您发现自己将这些内容放到班级中,请直接公开该成员并完成操作。

永远不要听那些会说“但是如果将来我们添加非平凡逻辑”的人呢?我看到的不仅仅是健康的琐碎吸气剂,而且已经使用了数十年,而且从未被非琐碎的东西所取代。

答案 2 :(得分:2)

常见的做法是:

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并返回std::shared_ptrstd::weak_ptr

答案 3 :(得分:1)

您可以返回对该成员的引用,而不是返回该成员的副本。这样就无需复制成员。

  

我考虑过这样做,但是我在互联网上读到它不是一个好主意,因为如果使用不当,可能会导致细分错误

解决方案是不要不好用它。

返回对成员的引用是很常见的模式,通常不建议这样做。尽管对于快速复制的类型,当不需要引用成员本身时,通常返回副本更好。

有一种避免复制和破坏封装的解决方案:使用共享指针,并从getter返回该共享指针的副本。但是,这种方法具有运行时成本,并且需要动态分配,因此并非适用于所有用例。


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