以下的新重载是否存在内存泄漏?

4
我遇到了以下代码:
    class a {
    public:

        void *  operator new(size_t l, int nb);
        double  values;
    };
void *a::operator new (size_t l,int n)
{
    return new char[l+ (n>1 ? n - 1 : 0)*sizeof(double)];
}

据我所知,它被用来创建一个类似于数组的结构,从"values"开始:

double* Val = &(p->a->values) + fColumnNumber;

我的问题是:是否存在内存泄漏?我对重载new运算符非常陌生,但我相当确定分配的内存没有正确释放。那是否意味着我永远不能在堆栈中创建“a”类?
谢谢

2
你展示的代码根本没有释放内存。请展示这段代码,否则我们无法判断是否存在内存泄漏。除非确实缺少operator delete,否则我不认为有先验理由怀疑内存泄漏。 - Konrad Rudolph
1
它确实丢失了,这就是我所拥有的。 - lezebulon
是的,无论如何,您都需要删除重载运算符。是什么让您认为重载 new 会以某种不同的方式工作呢? - Mr Lister
啊,这让问题更有趣了。 - Konrad Rudolph
@KonradRudolph 为什么这会让问题更有趣呢?现在它只是一个简单的缺少析构函数的问题而已。 - Mr Lister
@MrLister 这更有趣,因为我不知道答案:我不知道默认的 ::operator delete 是否能够为这个自定义分配器正确地释放相应数量的内存。 - Konrad Rudolph
5个回答

5
我相信从技术上讲,它目前会产生未定义行为,尽管这是一种几乎不会引起可见副作用的UB形式(它使用了new [], 但我相信它会与delete匹配 - 但对于char来说,这通常不会引起可见问题)。
在我看来,更糟糕的是它使用一个新的表达式来分配应该是原始字节而不是对象的内存。如果我在做的话,我会这样写:
void *a::operator new (size_t l,int n)
{
    return ::operator new(l+ (n>1 ? n - 1 : 0)*sizeof(double));
}

您需要将其与以下内容匹配:

void a::operator delete(void *block)
{
    ::operator delete(block);
}

+1 表示指出这是未定义行为,但不会对任何人造成伤害 是一个很好的替代方案。 - Mahmoud Al-Qudsi
@lezebulon:主要是如果你有一个operator new,那么你应该有一个匹配的operator delete,即使只是为了让它明显正确,而且你没有忘记什么。 - Jerry Coffin
谢谢你的回答,我担心的是在调用delete时只会释放sizeof(a)字节。我仍然不确定为什么所有分配的内存都会被释放。 - lezebulon

1

我不明白为什么在 a * 上调用默认的 operator delete 不能正确地释放由这个自定义的 operator new 分配的内存。最好的方法是编写一些代码并找出答案,虽然与 rob05c 的技术相比,我可能会在像 valgrind 这样的分析器中运行它。我假设提问者看到了内存泄漏的情况,并怀疑这是原因,因此围绕这个操作符编写一个测试用例似乎是值得的努力。

显然,如果没有人在之后实际删除它,它将会泄漏...

我会质疑重写 new 的必要性,但我也假设这是别人的代码。


0

这很容易找到。编写一个循环,构建和析构大量的a,并观察您的内存使用情况。如果有泄漏,内存使用量将会相当快地上升。


那几乎什么也没说,因为标准没有规定实现如何跟踪内存。 - Konrad Rudolph

0

目前代码没有问题,但是在使用这个类的代码中,你需要使用delete[]而不是delete,因为它分配了一个数组。请注意,用户不会得到任何提示需要这样做 - 为他们重载删除运算符可能是个好主意。


0
1. 你绝对可以在栈上创建类“a”。 2. 有4种(实际上更多,但我们将坚持基础知识)新的和删除方法签名,你应该知道。 void* operator new (std::size_t size) throw (std::bad_alloc); void* operator new[] (std::size_t size) throw (std::bad_alloc); void operator delete (void* ptr) throw (); void operator delete[] (void* ptr) throw (); 你正在“operator new”方法中分配一个数组,这应该在“operator new []”方法中完成。这将消除您的错误检查。编写“operator new”和“operator new []”两者。 3. 别忘了,你想给调用者一个类型为“a”的对象(a myA = new a ),所以确保返回“a”,而不是char *,因此你还需要进行转换。 4. 你需要编写相应的delete[]和delete方法。 5. 回答你的问题,我认为它会泄漏内存。你提供的新签名称为“放置new”。这使你能够分配一个新指针,而不分配内存,但要给它指向的位置。例如:如果你需要一个指向特定内存地址的指针。 long z = 0x0F9877F80078; a myA = new(z) a [5]; // 5个指针,它们指向0x0F9877F80078

根据定义,placement-new运算符不应该分配内存,因此如果您这样做可能会泄漏。去掉第二个参数,现在您有两个版本的operator new,可以这样做,然后就可以了。别忘了返回一个对象“a”。

请查看IBM的信息中心: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr318.htm

还有参考或参考资料,cpluplus.com: http://www.cplusplus.com/reference/std/new


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接