You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中new表达式初始化抛异常时释放函数查找的异常行为问询

C++ new表达式初始化抛异常时的释放函数查找异常行为

初始测试场景

以下代码中,S的构造函数抛出异常,触发new表达式的释放逻辑:

#include <new>
#include <iostream>
#include <cstdlib>
struct alignas(32) S
{
    S() {throw 1;}
    void* operator new(std::size_t count, std::align_val_t al)
    {
        return ::operator new(count, al);
    }
    void operator delete(void* ptr, std::align_val_t al)
    {
        std::cerr << "aligned delete\n";
        ::operator delete(ptr, al);
    }
};
int main()
{
    try
    {
        S* ps = new S;
    }
    catch(...)
    {
    }
}

运行后输出aligned delete。

为S添加模板化delete函数后:

struct alignas(32) S
{
    // 原有成员省略
    template <typename... Args>
    void operator delete(void* ptr, Args... args)
    {
        std::cerr << "templated delete\n";
    }
    // 原有成员省略
};

运行输出仍为aligned delete;只有移除aligned delete函数后,才会输出templated delete。

标准规则与疑问

对照C++标准[expr.new#28]规则:

A declaration of a placement deallocation function matches the declaration of a placement allocation function if it has the same number of parameters and, after parameter transformations ([dcl.fct]), all parameter types except the first are identical. If the lookup finds a single matching deallocation function, that function will be called; otherwise, no deallocation function will be called. If the lookup finds a usual deallocation function and that function, considered as a placement deallocation function, would have been selected as a match for the allocation function, the program is ill-formed. For a non-placement allocation function, the normal deallocation function lookup is used to find the matching deallocation function ([expr.delete]).

存在以下疑问:

  • 标准未明确定义placement allocation function,是否指参数数量≥2的分配函数?
  • 当存在aligned delete与模板化delete两个匹配的释放函数时,为何未触发「无释放函数调用」的规则?
  • aligned delete属于常规释放函数,且匹配分配函数,按规则程序应非法,但实际可正常运行?

后续测试结果

  1. 仅保留单参数delete时:
void operator delete(void* ptr)
{
    std::cerr << "single-parameter delete\n";
    ::operator delete(ptr);
}

运行无输出且无警告,说明编译器将aligned new视为placement allocation function,与标准规则相悖。

  1. 将分配函数替换为单参数new时,行为符合预期:仅存在aligned delete或搭配模板化delete时输出aligned delete,仅保留模板化delete时无输出且有警告。

  2. destroying delete未被优先调用:

struct S
{
    S() { throw 1; }
    void operator delete(S* ptr, std::destroying_delete_t)
    {
        std::cerr << "destroying delete\n";
        ptr->~S();
        ::operator delete(ptr);
    }
    void operator delete(void* ptr)
    {
        std::cerr << "single-parameter delete\n";
        ::operator delete(ptr);
    }
};

运行输出single-parameter delete,但按[expr.delete]规则destroying delete应具有最高优先级,不过对象未构造完成是否不应考虑该函数?

核心疑问

上述测试行为是编译器不符合标准,还是对标准的理解存在偏差?

内容的提问来源于stack exchange,提问作者Blackteahamburger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:15:50