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

何时`T&`可捕获异常而`T`不可?MSVC中CT_ByReferenceOnly探究

MSVC中CT_ByReferenceOnly标志位的设置场景

在MSVC编译器中,抛出表达式的信息由ThrowInfo结构编码:

struct ThrowInfo {
    unsigned int attributes;
    PMFN pmfnUnwind;
    int pForwardCompat;
    int pCatchableTypeArray; // RVA to the catchable type array
};

可捕获类型数组用于编码能捕获该异常的类型(比如基类),相关结构定义如下:

struct CatchableType {
    unsigned int properties;
    int pType;
    TypeDescriptor* pType;
    PMD thisDisplacement;
    int sizeOrOffset;
    PMFN copyFunction;
};

struct CatchableTypeArray {
    int nCatchableTypes;
    int arrayOfCatchableTypes[nCatchableTypes];
};

CatchableType的properties成员包含多个标志位,其中与引用捕获相关的是CT_ByReferenceOnly:

#define CT_IsSimpleType 0x00000001 // type is a simple type
#define CT_ByReferenceOnly 0x00000002 // type must be caught by reference
#define CT_HasVirtualBase 0x00000004 // type is a class with virtual bases
#define CT_IsWinRTHandle 0x00000008 // type is a winrt handle
#define CT_IsStdBadAlloc 0x00000010 // type is a std::bad_alloc

当CT_ByReferenceOnly位被设置时,非引用参数的catch块无法匹配该异常——比如catch(T& t)可以捕获,而catch(T t)不行。通过修改二进制文件可以验证这一行为:以下程序原本会输出Hello,手动设置该位后会输出World。

#include <cstdio>

struct A {};

int main() {
    try {
        try {
            throw A{};
        } catch (A a) {
            std::printf("Hello\n");
        }
    } catch (A& a) {
        std::printf("World\n");
    }

    return 0;
}

已知如果T是抽象类型,编译器会要求通过引用捕获,但此时CT_ByReferenceOnly位并未设置。以下是MSVC中会设置该位的场景:

  • 类型无访问权限的拷贝构造函数:当异常类型的拷贝构造函数被标记为private/protected,或被删除(= delete)时,编译器无法生成拷贝操作满足值捕获,因此会设置CT_ByReferenceOnly位,强制必须通过引用捕获。
  • std::exception及其派生类:对于标准库中的异常类型,MSVC默认设置该位,确保异常通过引用捕获,避免对象切片问题。
  • WinRT句柄类型:结合CT_IsWinRTHandle标志位,WinRT句柄类型需通过引用或智能指针处理,编译器会同时设置CT_ByReferenceOnly位,禁止值捕获。
  • 自定义禁止拷贝的类型:如果类型通过= delete禁用拷贝构造和拷贝赋值,或是移动-only类型,编译器会设置该位,强制引用捕获。
  • std::bad_alloc等特殊标准类型:对应CT_IsStdBadAlloc标志位,MSVC会同时设置CT_ByReferenceOnly,确保这类内存分配异常只能通过引用捕获。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:57:19