分割错误而不是构造函数调用

Segmentation fault instead of constructor call

本文关键字:函数调用 错误 分割      更新时间:2023-10-16

我正在尝试修改内置分配函数:

#include <iostream>
#include <cstdlib>
#include <new>
struct A
{
    int a;
    A(){ std::cout << "Constructorn"; a = 3; }
    void* operator new(std::size_t t) noexcept
    {
        ::operator new(t);
        return NULL;
    }
};
int main()
{
    new A();
}

演示

我用segmentation fault代替构造函数调用。你能解释一下这种行为吗?

您有一个bug,因为对::operator new()的调用可能抛出std::bad_alloc,违反了特定于类的分配器的异常规范(zybox的答案显示了如何修复这个问题)。然而,这在这么小的程序中是不太可能发生的。在不提供operator delete()的情况下覆盖operator new()也是一个坏主意,尽管我找不到一个明确的要求,即两者必须在同一范围内找到。

从分配器返回空指针是指示分配失败的合法且正确的方式。在3.7.4.1中,标准规定:

分配函数如果分配存储失败,可以调用当前安装的new-handler函数(18.6.2.3)。[注:程序提供的分配函数可以通过std::get_new_handler函数(18.6.2.4)获得当前安装的new_handler的地址。]如果用非抛出异常规范(15.4)声明的分配函数分配存储失败,它应该返回一个空指针。任何其他分配函数如果分配存储失败,只能抛出与类型std::bad_alloc(18.6.2.1)的处理程序(15.3)匹配的异常(15.1)来表示失败。

在5.3.4中:

如果分配函数返回null,则不进行初始化,不调用分配函数,new-expression的值为null。

代码在::operator new()不抛出的路径上是合法的——main()中的表达式new A()计算为空指针,这是可以的,因为它永远不会被解引用。

也不应该调用构造函数。您应该得到的是内存泄漏,因为在分配器中没有对应于::operator new(t)::operator delete()调用。

您的函数操作符new包含null指针,因此实际上不返回任何内容。

null函数操作符等于return false;,或者只是return;,但要注意:如果不小心,使用new操作符复制指针会导致内存泄漏。为了解决这个问题,当你完成时,只需delete(t)

下面的代码将解决您的问题:

#include <iostream>
#include <cstdlib>
#include <new>
struct A
{
    int a;
    A(){ std::cout << "Constructorn"; a = 3; }
    void* operator new(std::size_t t) noexcept
    {
        return ::operator new(t, std::nothrow);
    }
};
int main()
{
    new A();
}

原始代码只是从A::operator new返回NULL,悄悄地忘记了::operator new的返回结果(内存泄漏)。崩溃的原因是返回的指针随后被用作新的A对象的this指针。由于该指针是NULL,构造函数对对象所做的任何操作(赋值a = 3)都是对NULL的解引用。这导致了分割冲突。Zyboxinternational上面的答案给出了一个很好的解决方案,前面两个海报的评论都非常相关。