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

使用shared_ptr/unique_ptr自动关闭Win32 HANDLE的代码有效性咨询

Win32 HANDLE智能指针管理问题解析

我不清楚如何自行验证这一点,因此在此提问。我刚接触智能指针,想咨询:在以下代码示例中,所有Win32 HANDLE是否都会被自动关闭?还有其他需要处理的事项吗?另外,我无法使用CHandle类。

你的原始代码如下:

#include <stdio.h>
#include <windows.h>
#include <fileapi.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <memory>

struct Deleter
{
    void operator()(HANDLE* h)
    {
        CloseHandle(*h);
    }
};

void Close(HANDLE* handle)
{
    CloseHandle(*handle);
}

void helper()
{
    std::wstring str = L"Project2.exe 30 30";
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    CreateProcess(NULL, str.data(), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
    STARTUPINFO li = { sizeof(si) };
    PROCESS_INFORMATION ki;
    CreateProcess(NULL, str.data(), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &li, &ki);

    std::unique_ptr<HANDLE, Deleter> xx = std::unique_ptr<HANDLE, Deleter>(&pi.hProcess);
    std::unique_ptr<HANDLE, Deleter> yy(&pi.hThread);
    std::shared_ptr<HANDLE> zz(&ki.hProcess, Close);
    std::shared_ptr<HANDLE> ww(&ki.hThread, Close);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    helper();
}

首先明确:你的代码不会正确管理HANDLE,反而有未定义行为风险

核心问题出在智能指针的使用方式错误:

  • 你让unique_ptr/shared_ptr管理的是栈上HANDLE变量的地址,而不是HANDLE资源本身。智能指针的设计意图是持有资源的所有权,这里传递&pi.hProcess(栈变量地址),虽然deleter会调用CloseHandle(*h)关闭句柄,但存在隐患:如果栈变量被覆盖、后续代码误操作指针地址,都会导致错误。
  • 没有检查CreateProcess的返回值:如果进程创建失败,pi/ki里的HANDLE是NULL,虽然CloseHandle(NULL)不会报错,但你无法感知错误,也会做无意义的操作。
  • 存在重复释放风险:如果后续代码手动调用CloseHandle,加上智能指针的自动调用,会导致重复关闭句柄,触发未定义行为。

正确的智能指针管理HANDLE方式

我们让智能指针直接持有HANDLE资源,自定义deleter直接操作HANDLE,而不是HANDLE的指针。

方案1:unique_ptr + 自定义仿函数deleter

#include <stdio.h>
#include <windows.h>
#include <fileapi.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <memory>

// 自定义deleter,直接处理HANDLE,判断无效句柄
struct HandleDeleter {
    void operator()(HANDLE h) const {
        if (h != INVALID_HANDLE_VALUE && h != NULL) {
            CloseHandle(h);
        }
    }
};

// 定义别名简化使用
using UniqueHandle = std::unique_ptr<void, HandleDeleter>;

void helper()
{
    std::wstring str = L"Project2.exe 30 30";
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi{};

    // 必须检查CreateProcess是否成功
    if (CreateProcessW(NULL, str.data(), nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi)) {
        // 直接把HANDLE交给智能指针,转移所有权
        UniqueHandle processHandle(pi.hProcess);
        UniqueHandle threadHandle(pi.hThread);
        // 将原结构体中的HANDLE置空,避免后续误操作
        pi.hProcess = NULL;
        pi.hThread = NULL;
    } else {
        // 处理错误,打印错误码
        printf("CreateProcess失败,错误码:%lu\n", GetLastError());
    }

    STARTUPINFO li = { sizeof(li) };
    PROCESS_INFORMATION ki{};
    if (CreateProcessW(NULL, str.data(), nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &li, &ki)) {
        // shared_ptr同样直接管理HANDLE
        std::shared_ptr<void> sharedProcessHandle(ki.hProcess, HandleDeleter());
        std::shared_ptr<void> sharedThreadHandle(ki.hThread, HandleDeleter());
        ki.hProcess = NULL;
        ki.hThread = NULL;
    } else {
        printf("CreateProcess失败,错误码:%lu\n", GetLastError());
    }
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    helper();
    return 0;
}

方案2:shared_ptr + 单独的清理函数

如果你偏好单独的清理函数,也可以这么写:

// 单独的清理函数
void CloseWin32Handle(HANDLE h) {
    if (h != INVALID_HANDLE_VALUE && h != NULL) {
        CloseHandle(h);
    }
}

// 使用时:
std::shared_ptr<void> sharedProcessHandle(ki.hProcess, CloseWin32Handle);

其他需要注意的事项

  • 一定要检查Win32 API的返回值:CreateProcess失败时返回FALSE,这时候句柄是无效的,及时处理错误能避免无效操作。
  • 避免重复释放:把句柄交给智能指针后,将原结构体中的句柄置为NULL,防止后续手动调用CloseHandle导致重复释放。
  • 区分无效句柄类型:有些Win32函数返回INVALID_HANDLE_VALUE(比如文件操作),有些返回NULL(比如进程创建),deleter里同时判断这两种情况更安全。
  • 用void作为智能指针模板参数:HANDLE本质是void*,用void作为模板参数可以避免不必要的类型转换,deleter直接处理HANDLE即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:50:22