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

std::any实现中unique_ptr的作用及析构未触发问题咨询

关于libcxx中std::any大对象处理函数的异常安全问题

libcxx中std::any的大对象处理函数定义如下:

template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY
static _Tp& __create(any & __dest, _Args&&... __args) {
    typedef allocator<_Tp> _Alloc;
    typedef allocator_traits<_Alloc> _ATraits;
    typedef __allocator_destructor<_Alloc> _Dp;
    _Alloc __a;

    unique_ptr<_Tp, _Dp> __hold(_ATraits::allocate(__a, 1), _Dp(__a, 1));
    _Tp * __ret = __hold.get();
    _ATraits::construct(__a, __ret, _VSTD::forward<_Args>(__args)...);

    __dest.__s_.__ptr = __hold.release();
    __dest.__h_ = &_LargeHandler::__handle;
    return *__ret;
}

问题

此处用unique_ptr持有原始指针是否为了应对构造函数抛出异常时的安全问题?我编写了如下测试代码,但析构函数完全未被调用:

#include <any>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <cstdlib>

using namespace std;

struct A {
    double b;
    double c;
    double d;
    void* p;

    A() {
        p = malloc(50);
        std::cout << "constructing" << std::endl;
        throw std::exception();
    }

    ~A() {
        free(p);
        std::cout << "deconstructing " << std::endl;
    }
};

int main() {
    std::any a;

    try {
        __create(a);
    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

解答

  1. unique_ptr的作用确实是异常安全保障
    这段代码里用unique_ptr绑定分配的内存和自定义析构器__allocator_destructor,核心目的就是处理构造函数抛出异常的情况:
  • _ATraits::allocate成功分配内存后,若后续_ATraits::construct(即对象构造)抛出异常,unique_ptr会在函数退出时自动触发析构逻辑,调用__allocator_destructor释放之前分配的内存,避免内存泄漏。
  • 如果构造成功,就通过__hold.release()把指针转移给std::any的内部存储,此时unique_ptr不再持有该指针,不会触发释放。
  1. 测试代码中析构未调用的原因
    你的测试代码存在两个关键问题:
  • 模板参数缺失:__create是模板函数,需要明确指定_Tp类型(也就是你的struct A),正确调用应为__create<A>(a)。不指定模板参数的话,编译器无法推导_Tp,实际这段调用可能根本没有正确实例化__create函数,自然不会执行内存分配和构造逻辑。
  • 调用私有函数的未定义行为:__create是libcxx的内部私有函数,直接调用属于未定义行为,不同版本的libcxx可能有不同实现,甚至编译报错。正确的测试方式应该通过std::any的公开接口(比如emplace<A>())触发大对象创建逻辑。

修改后的测试代码(使用公开接口):

#include <any>
#include <iostream>
#include <stdexcept>
#include <cstdlib>

using namespace std;

struct A {
    double b;
    double c;
    double d;
    void* p;

    A() {
        p = malloc(50);
        std::cout << "constructing" << std::endl;
        throw std::exception();
    }

    ~A() {
        free(p);
        std::cout << "deconstructing " << std::endl;
    }
};

int main() {
    std::any a;

    try {
        a.emplace<A>(); // 使用std::any的公开接口
    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

运行这段代码就能看到deconstructing的输出,证明异常发生时内存被正确释放了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 08:02:03