内存分配操作符重载?
下面这句话来自C++ 和 Java 的积极遗产 由 Bruce Eckel 撰写,关于 C++ 中的运算符重载:
C++既有栈分配又有堆分配 分配,你必须超载你的 操作员处理所有情况和 不会造成内存泄漏。 难的 确实如此。
我不明白运算符重载与内存分配有何关系。 谁能解释一下它们是如何相关的?
The sentence below is from, The Positive Legacy of C++ and Java by Bruce Eckel, about operator overloading in C++:
C++ has both stack allocation and heap
allocation and you must overload your
operators to handle all situations and
not cause memory leaks. Difficult
indeed.
I do not understand how operator overloading has anything to do with memory allocation. Can anyone please explain how they are correlated?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可以想象几种可能的解释:
首先,在 C++ 中,
new
和delete
实际上都是运算符; 如果您选择通过重载这些运算符来为对象提供自定义分配行为,则必须非常小心,以确保不会引入泄漏。其次,某些类型的对象要求您重载
operator=
以避免内存管理错误。 例如,如果您有一个引用计数智能指针对象(如 Boost shared_ptr),则必须实现operator=
,并且必须确保正确执行。 考虑这个损坏的示例:此处的
operator=
实现已损坏,因为它不管理mData
和other.mData
上的引用计数:不会减少mData
上的引用计数,从而导致泄漏; 并且它不会增加 other.mData 上的引用计数,从而导致可能的内存故障,因为所指向的对象可能会在所有实际引用消失之前被删除。请注意,如果您没有为您的类显式声明自己的
operator=
,编译器将提供一个默认实现,其行为与此处所示的实现相同 - 也就是说,在这种特殊情况下完全损坏。因此,正如文章所说——在某些情况下,您必须重载运算符,并且必须小心正确地处理所有情况。
编辑:抱歉,我没有意识到参考文献是一篇在线文章,而不是一本书。 即使读完整篇文章后,也不清楚其意图是什么,但我认为埃克尔可能指的是我上面描述的第二种情况。
I can imagine a couple possible interpretations:
First, in C++
new
anddelete
are both actually operators; if you choose to provide custom allocation behavior for an object by overloading these operators, you must be very careful in doing so to ensure you don't introduce leaks.Second, some types of objects require that you overload
operator=
to avoid memory management bugs. For example, if you have a reference counting smart pointer object (like the Boost shared_ptr), you must implementoperator=
, and you must be sure to do so correctly. Consider this broken example:The
operator=
implementation here is broken because it doesn't manage the reference counts onmData
andother.mData
: it does not decrement the reference count onmData
, leading to a leak; and it does not increment the reference count onother.mData
, leading to a possible memory fault down the road because the object being pointed to could be deleted before all the actual references are gone.Note that if you do not explicitly declare your own
operator=
for your classes, the compiler will provide a default implementation which has behavior identical to the implementation shown here -- that is, completely broken for this particular case.So as the article says -- in some cases you must overload operators, and you must be careful to handle all situations correctly.
EDIT: Sorry, I didn't realize that the reference was an online article, rather than a book. Even after reading the full article it's not clear what was intended, but I think Eckel was probably referring to situations like the second one I described above.
new 和 delete 实际上是 C++ 中的运算符,您可以覆盖它们以提供您自己的自定义内存管理。 请查看此处的示例。
new and delete are actually operators in C++ which you can override to provide your own customized memory management. Take a look at the example here.
运算符是函数。 仅仅因为它们添加了语法糖并不意味着你不需要小心记忆。 您必须像管理任何其他成员/全局/友元函数一样管理内存。
当您实现包装指针类时重载时,这一点尤其重要。
然后通过重载
operator+
或operator+=
进行字符串连接。 查看basic_string
模板以获取更多信息。Operators are functions. Just because they add syntactic sugar does not mean you need not be careful with memory. You must manage memory as you would with any other member/global/friend function.
This is particularly important when you overload the when you implement a wrapper pointer class.
There is then string concatenation, by overloading the
operator+
oroperator+=
. Take a look at thebasic_string
template for more information.如果您要比较 Java 和 C++ 之间的运算符重载,您不会谈论 new 和 delete - Java 没有为 new 公开足够的内存管理细节,并且没有不需要删除。
您不能重载指针类型的其他运算符 - 至少一个参数必须是类或枚举类型,因此他不能谈论为指针提供不同的运算符。
因此,C++ 中的运算符对值或对值的 const 引用进行操作。
对于对值或对值的常量引用进行操作的运算符来说,返回值以外的任何内容是非常不寻常的。
除了所有 C++ 函数常见的明显错误之外 - 返回对堆栈分配对象的引用(与内存泄漏相反),或返回对使用 new 创建的对象而不是值的引用(在学习之前,在职业生涯中通常不会超过一次),很难想象常见操作员有记忆问题的场景。
因此,无需根据操作数是根据正常使用模式分配堆栈还是堆来创建多个版本。
运算符的参数是作为值或引用传递的对象。 C++ 中没有可移植的机制来测试对象是否分配到堆或堆栈。 如果对象是按值传递的,则它将始终位于堆栈上。 因此,如果需要更改这两种情况下运算符的行为,则不可能在 C++ 中进行移植。 (在许多操作系统上,您可以测试指向对象的指针是否位于通常用于堆栈的空间或通常用于堆的空间中,但这既不可移植也不完全可靠。)(此外,即使您可以使用运算符它采用两个指针作为参数,没有理由相信这些对象是堆分配的,因为它们是指针,而 C++ 中根本不存在该信息)
您得到的唯一重复是对于诸如operator[]之类的情况,其中相同。运算符既用作访问器又用作修改器。 那么有一个const和一个非const版本是很正常的,所以如果接收者不是const的话你可以设置该值。 这是一件好事 - 无法改变已标记为常量的对象(其可公开访问的状态)。
If you are comparing operator overloading between Java and C++, you wouldn't be talking about
new
anddelete
- Java doesn't expose enough memory management detail for new, and doesn't need delete.You can't overload the other operators for pointer types - at least one argument must be a class or enumerated type, so he can't be talking about providing different operators for pointers.
So operators in C++ operate on values or const references to values.
It would be very unusual for operators which operator on values or const references to values to return anything other than a value.
Apart from obvious errors common to all C++ functions - returning a reference to a stack allocated object (which is the opposite of a memory leak), or returning a reference to an object created with
new
rather than a value (which is usually done no more than once in a career before being learnt), it would be hard to come up with a scenario where the common operators have memory issues.So there isn't any need to create multiple versions depending on whether the operands are stack or heap allocated based on normal patterns of use.
The arguments to an operator are objects passed as either values or references. There is no portable mechanism in C++ to test whether an object was allocated heap or stack. If the object was passed by value, it will always be on the stack. So if there was a requirement to change the behaviour of the operators for the two cases, it would not be possible to do so portably in C++. (you could, on many OSes, test whether the pointer to the object is in the space normally used for stack or the space normally used for heap, but that is neither portable nor entirely reliable.) (also, even if you could have operators which took two pointers as arguments, there's no reason to believe that the objects are heap allocated just because they are pointers. that information simply doesn't exist in C++)
The only duplication you get is for cases such as operator[] where the same operator is used as both an accessor and a mutator. Then it is normal to have a const and a non-const version, so you can set the value if the receiver is not const. That is a good thing - not being able to mutate (the publicly accessible state of) objects which have been marked constant.