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

Android NDK中std::rethrow_exception无法被std::exception捕获问题

Android上std::exception_ptr重抛异常无法匹配std::exception的原因与解决方法

问题描述

我有一个从Java调用C++代码的Android应用,测试代码如下:

try {
  throw std::runtime_error("Test exception");
} catch (...) {
  auto eptr = std::current_exception();
  try {
    std::rethrow_exception(eptr);
  } catch (const std::exception& e) {
    std::cout << "Caught std::exception: " << e.what() << std::endl;
  } catch (...) {
    std::cout << "Caught unknown exception" << std::endl;
  }
}
  • iOS平台:代码正常进入catch (const std::exception& e)块,输出预期内容 ✅
  • Android平台:代码进入catch (...)块,输出未知异常 ❌

疑问:为何相同标准库代码跨平台表现不同?Android的STL是否不支持std::exception_ptr?

环境配置信息

build.gradle配置

android {
  namespace "com.margelo.nitro"

  ndkVersion getExtOrDefault("ndkVersion")
  compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")

  defaultConfig {
    minSdkVersion getExtOrIntegerDefault("minSdkVersion")
    targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")

    externalNativeBuild {
      cmake {
        cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
        arguments "-DANDROID_STL=c++_shared",
                  "-DANDROID_TOOLCHAIN=clang",
                  "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
        abiFilters (*reactNativeArchitectures())

        buildTypes {
          debug {
            cppFlags "-O1 -g"
          }
          release {
            cppFlags "-O2"
          }
        }
      }
    }
  }

  externalNativeBuild {
    cmake {
      path "CMakeLists.txt"
    }
  }

  buildFeatures {
    buildConfig true
    prefab true
    prefabPublishing true
  }

  packagingOptions {
    pickFirst "**/libc++_shared.so"
    excludes = [
      "META-INF",
      "META-INF/**"
    ]
  }
  // ...
}

CMake配置

project(NitroModules)
cmake_minimum_required(VERSION 3.9.0)
set (CMAKE_CXX_STANDARD 20)

add_library(NitroModules SHARED MyFile.cpp)

// 链接所需依赖库,如fbjni、android、ReactAndroid等

运行环境

React Native环境,使用SoLoader,通过Java加载库:

System.loadLibrary("NitroModules");

原因分析

Android NDK的c++_shared STL完全支持std::exception_ptr,问题根源在于异常类型的RTTI信息跨SO边界传递异常:

  1. 当在一个SO中抛出std::runtime_error,通过std::current_exception捕获异常指针再重抛时,若异常类型的type_info在不同SO中无法匹配(比如主SO与依赖的STL SO之间符号解析不一致),就会导致重抛后无法识别std::exception类型。
  2. 配置中使用c++_shared意味着STL是独立SO(libc++_shared.so),若你的C++库与其他依赖库(如React Native相关库)使用的STL版本不一致,或符号加载顺序异常,会引发RTTI信息不匹配。
  3. React Native的SoLoader加载SO时,可能改变符号解析路径,进一步导致异常类型识别失败。

解决方法

  1. 统一所有依赖库的STL版本:
    确保所有链接的第三方库(如fbjni、ReactAndroid)都使用c++_shared,禁止混合使用c++_static和c++_shared,避免RTTI与异常处理的符号冲突。

  2. 明确CMake的STL配置:
    在CMakeLists.txt中显式指定STL类型,确保编译阶段统一:

    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_ANDROID_STL_TYPE c++_shared)
    
  3. 升级NDK版本:
    建议使用NDK r25及以上版本,旧版本可能存在C++20异常处理的兼容性问题,新版本对std::exception_ptr的实现更稳定。

  4. 防止RTTI被优化丢失:
    Release模式下的-O2优化可能会剔除type_info数据,可添加编译选项保留RTTI信息:

    release {
      cppFlags "-O2 -fno-rtti-data-elimination"
    }
    
  5. 简化异常捕获逻辑:
    若重抛方式暂时无法解决,可在第一次catch时直接捕获具体异常类型,跳过exception_ptr传递:

    try {
      throw std::runtime_error("Test exception");
    } catch (const std::exception& e) {
      std::cout << "Caught std::exception: " << e.what() << std::endl;
    } catch (...) {
      std::cout << "Caught unknown exception" << std::endl;
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:52:36