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边界传递异常:
- 当在一个SO中抛出
std::runtime_error,通过std::current_exception捕获异常指针再重抛时,若异常类型的type_info在不同SO中无法匹配(比如主SO与依赖的STL SO之间符号解析不一致),就会导致重抛后无法识别std::exception类型。 - 配置中使用
c++_shared意味着STL是独立SO(libc++_shared.so),若你的C++库与其他依赖库(如React Native相关库)使用的STL版本不一致,或符号加载顺序异常,会引发RTTI信息不匹配。 - React Native的SoLoader加载SO时,可能改变符号解析路径,进一步导致异常类型识别失败。
解决方法
统一所有依赖库的STL版本:
确保所有链接的第三方库(如fbjni、ReactAndroid)都使用c++_shared,禁止混合使用c++_static和c++_shared,避免RTTI与异常处理的符号冲突。明确CMake的STL配置:
在CMakeLists.txt中显式指定STL类型,确保编译阶段统一:set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_ANDROID_STL_TYPE c++_shared)升级NDK版本:
建议使用NDK r25及以上版本,旧版本可能存在C++20异常处理的兼容性问题,新版本对std::exception_ptr的实现更稳定。防止RTTI被优化丢失:
Release模式下的-O2优化可能会剔除type_info数据,可添加编译选项保留RTTI信息:release { cppFlags "-O2 -fno-rtti-data-elimination" }简化异常捕获逻辑:
若重抛方式暂时无法解决,可在第一次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
相关产品推荐
相关产品推荐

