operator new和operator new[]有什么区别?

3

我已经重载了全局的operator new/delete/new[]/delete[],但简单的测试表明,虽然我的new和delete版本被正确调用,但使用new[]和delete[]进行简单的数组分配和删除会导致newaop.cpp和delete2.cpp中的实现被调用。

例如,以下代码:

int* a = new int[10];

在newaop.cpp中调用operator new[],进而调用了我的版本的operator new。所以它们似乎是全局重载的,但由于某些原因不包括数组版本。我是否遗漏了什么?

编辑:我的运算符实现在一个单独的项目中,编译为库并静态链接。回想起来,这可能有助于包含在原始帖子中,因为它可能与此有关。尽管我仍然无法弄清楚为什么只影响数组版本。


newaop.cppdelete2.cpp是什么? - Gregory Pakosz
看起来一切都按预期工作:new int[10] 调用了你的函数。你能提供一个完整的测试案例并解释实际行为与你期望的有何不同吗? - Roger Pate
你能否编写一个只包含一个文件的测试用例,以展示出现了意外行为?如果不能,那么两个文件呢?并且请粘贴它们的完整内容。如果你能做到这一点,很可能我和其他人都能明显地看出问题所在,但现在我无法找到任何单一的原因。 - Roger Pate
我们需要更多的实际代码来回答你的问题。 - Omnifarious
非常惊讶我找不到这个的副本。相关链接:https://dev59.com/N3I-5IYBdhLWcg3wVWpi - dmckee --- ex-moderator kitten
显示剩余2条评论
4个回答

3

我不知道你如何重载operator new[],但我刚刚尝试了MSVC2008:

void* operator new[](size_t size)
{
  return 0;
}

int main()
{
  int* a = new int[5];
}

上面的代码有效地调用了我有问题的operator new[]实现。
所以,我的猜测是:由于某种原因,您未能重载operator new[],因此您的程序使用编译器版本的operator new[],它依赖于operator new来分配内存。由于您重载了operator new,因此会调用您的实现。

尽管你的有缺陷的替换违反了operator new[]的要求并引发了未定义的行为,但任何事情都可能发生! :P - Roger Pate
1
我的目的只是为了在返回空指针的operator new[]中进行步进调试。我不想在我的示例中粘贴一个防弹实现,所以我选择编写一个明显有缺陷且不能作为参考的实现 :) - Gregory Pakosz
这就是为什么我说它是半开玩笑的。:P 任何时候调用未定义行为都是不好的,但在示例中可能会隐藏重要问题,比如尝试使用上述方法new int[5](),我认为值得指出的是,在C++中你实际上不能像这样实现new[]。 - Roger Pate
我认为你的重载没有问题,我的也很类似。由于我只是为了特定的目的使用它,我不希望它模拟标准函数的行为,例如我不想让我的重载抛出异常或调用新的处理程序。 - Flawe
实际上,在分配失败时,我只是中止程序,因为我认为这在我的应用程序中永远不会发生。 - Flawe
显示剩余3条评论

0

operator new分配一个对象并调用其构造函数。new[]分配n个对象并调用n个构造函数。

编辑:具有多个new[]和delete[]重载可能被认为是有点奇怪的。编译器如何知道要链接哪一个?您能否发布您的重载内容?如果在exe中不链接newaop和delete2,您的重载是否会被调用(即您的实现是唯一的实现)?


我指的是与我的问题有关的差异。如果我表达不够清楚,对不起。 - Flawe
1
Goz:您可以替换某些函数(“替换函数”),请参见18.4.1节。 - Roger Pate
newaop和delete2似乎是Visual Studio特有的,并且会链接到您的代码中,这不是我选择的。我没有发布任何代码的原因是它们分散在各处,这让我想起了什么。我的运算符实现在一个单独的项目中,该项目被编译为库并静态链接。回顾一下,将其包含在原始帖子中可能很有用,因为它可能与此有关。尽管如此,我仍然无法弄清楚为什么只有数组版本受到影响。 - Flawe
你得试一下,因为我们几乎无法提供更多信息...它应该可以工作...但如果没有看到代码,我们怎么能找出问题所在呢? - Goz
从技术上讲,operator new 只为一个对象分配内存,而 operator new[] 则为 n 个对象分配内存。它们都不调用任何构造函数 - 这是 new 表达式的工作。 - Lstor
显示剩余3条评论

0
你告诉我们你的代码有 bug,但没有发布任何代码 :vP。我的猜测是你在重载的参数中使用了 int 而不是 size_t。某些重载可能被调用是因为编译器决定在这种情况下宽容一些。

0

好的,我已经解决了这个问题,所以在这里发布一下,以防其他人也遇到同样的问题。

操作符没有被调用的原因是因为我的实现位于库中,而不是调用操作符的项目中。实际上,由于你只需要包含操作符的实现,它们已经全局定义了,我只在我的库中指定了操作符的实现(这是错误的步骤)。代码显然只包括库中的头文件,并且无法看到实现。此外,Visual Studio似乎将newaop.cpp和delete2.cpp链接到了我的应用程序中。这两个文件包含了operator new[]和operator delete[]的实现(但不包括常规的new/delete!)。这很可能是编译器选择这两个实现而不是我在库中的实现的原因。

解决方法是将我重载操作符的实现移动到库中的一个头文件中,并直接从我的代码中包含它。


1
你不应该把重载的实现放在头文件中。标准要求默认版本应该被你的“程序”中的实现所替换,这个程序应该包括静态库。你可以把这个回答放在原问题中,或者标记为已选择的答案(如果可以的话),因为它会一直停留在页面底部。 - Potatoswatter
是的,它包括库。问题在于Visual Studio链接了newaop.cpp和delete2.cpp,它们也包括那些运算符的实现,编译器选择了它们而不是我的代码。由于这仅影响数组版本的运算符!常规运算符的定义方式完全相同,它们可以正常工作。 - Flawe

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