运算符重载内存分配?

时间:2009-03-25 05:12:51

标签: c++ memory-leaks operator-overloading

以下句子来自Bruce Eckel的 The Positive Legacy of C++ and Java ,关于C ++中的运算符重载:

  

C ++既有堆栈分配又有堆   分配,你必须超载你的   操作员处理所有情况和   不会导致内存泄漏。难   确实

我不明白运算符重载与内存分配有什么关系。有人可以解释一下它们是如何相关的吗?

4 个答案:

答案 0 :(得分:3)

我可以想象几种可能的解释:

首先,在C ++中newdelete都是运算符;如果您选择通过重载这些运算符来为对象提供自定义分配行为,那么您必须非常小心,以确保不会引入泄漏。

其次,某些类型的对象需要重载operator=以避免内存管理错误。例如,如果您有一个引用计数智能指针对象(如Boost shared_ptr),则必须实现operator=,并且必须确保正确执行此操作。考虑一下这个破碎的例子:

template <class T>
class RefCountedPtr {
public:
    RefCountedPtr(T *data) : mData(data) { mData->incrRefCount(); }
    ~RefCountedPtr() { mData->decrRefCount(); }
    RefCountedPtr<T>& operator=(const RefCountedPtr<T>& other) {
        mData = other.mData;
        return *this;
    }
    ...
protected:
    T *mData;
};

此处的operator=实施已被删除,因为它无法管理mDataother.mData上的引用计数:它不会减少mData上的引用计数,导致泄漏;并且它不会增加other.mData上的引用计数,从而导致可能的内存故障,因为在所有实际引用消失之前,可以删除指向的对象。

请注意,如果您没有为您的类显式声明自己的operator=,编译器将提供一个默认实现,其行为与此处显示的实现相同 - 也就是说,对于此特定情况完全中断。

正如文章所说 - 在某些情况下,你必须重载操作符,你必须小心处理所有情况。

编辑:对不起,我没有意识到这篇文章是一篇在线文章,而不是一本书。即使在阅读完整篇文章之后,目前还不清楚是什么意思,但我认为Eckel可能指的是像我上面描述的那样的情况。

答案 1 :(得分:1)

new和delete实际上是C ++中的运算符,您可以覆盖它们以提供自己的自定义内存管理。看看这里的example

答案 2 :(得分:0)

运算符是函数。仅仅因为他们添加语法糖并不意味着你不必小心记忆。您必须像管理任何其他成员/全局/朋友功能一样管理内存。

当您实现包装器指针类时重载时,这一点尤其重要。

通过重载operator+operator+=,可以进行字符串连接。有关详细信息,请查看basic_string模板。

答案 3 :(得分:0)

如果您正在比较Java和C ++之间的运算符重载,那么您就不会讨论newdelete - Java没有为新的内容提供足够的内存管理细节,也不需要删除。

你不能为指针类型重载其他运算符 - 至少有一个参数必须是类或枚举类型,因此他不能谈论为指针提供不同的运算符。

因此,C ++中的运算符对值或const引用值进行操作。

运算符对值或const引用值的运算符返回值以外的任何值都是非常不寻常的。

除了所有C ++函数常见的明显错误之外 - 返回对堆栈分配对象的引用(与内存泄漏相反),或返回对使用new而不是值创建的对象的引用(通常在学习之前在职业生涯中不会超过一次),很难想出常见操作员有内存问题的情况。

因此,根据正常使用模式,操作数是堆栈还是堆分配,无需创建多个版本。

运算符的参数是作为值或引用传递的对象。 C ++中没有可移植的机制来测试对象是分配堆还是堆栈。如果对象是按值传递的,它将始终在堆栈上。因此,如果需要在两种情况下更改运算符的行为,则无法在C ++中进行移植。 (在许多操作系统上,您可以测试指向对象的指针是否位于通常用于堆栈的空间或通常用于堆的空间中,但这既不便携也不完全可靠。)(即使您可以拥有运算符)以两个指针作为参数,没有理由相信对象是堆分配只是因为它们是指针。这些信息在C ++中根本不存在)

您获得的唯一重复是诸如operator []之类的情况,其中相同的运算符用作访问器和增变器。那么有一个const和一个非const版本是正常的,所以你可以设置接收器不是const的值。这是一件好事 - 无法改变(可公开访问的状态)已标记为常量的对象。