如何在不生成副本的情况下使用 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_ptr
或 std::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,已经存在了几十年,而且从未被不重要的东西所取代。
我想知道如何将 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_ptr
或 std::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,已经存在了几十年,而且从未被不重要的东西所取代。