如何从函数中正确返回指针

时间:2017-09-20 17:27:24

标签: c++ pointers winapi return

我有以下功能:

std::wstring GetNetStatus()
{
    NETSETUP_JOIN_STATUS bufType;
    ::ZeroMemory(&bufType, sizeof(NETSETUP_JOIN_STATUS));

    LPWSTR buf;
    CHECK_OS_ERROR(::NetGetJoinInformation(nullptr, &buf, &bufType) == NERR_Success);

    std::wstring group(buf);
    ::NetApiBufferFree(buf);

    return group;
}

我需要返回一个LPWSTR值但是根据我正在使用的API,我需要在离开函数范围之前释放这个指针。

将一个LPWSTR值分配给STL字符串并将其返回或是否有其他一些技巧是否正确?

2 个答案:

答案 0 :(得分:2)

您所展示的内容在技术上是正确的。

但是,请注意,当std::wstringbuf复制字符数据时,它会使 potential 引发异常,因此您应该准备好处理这是为了避免任何可能的内存泄漏。

您可以使用__try/__finally

std::wstring GetNetStatus()
{
    std::wstring result;

    NETSETUP_JOIN_STATUS bufType;
    ::ZeroMemory(&bufType, sizeof(NETSETUP_JOIN_STATUS));

    LPWSTR buf;
    CHECK_OS_ERROR(::NetGetJoinInformation(nullptr, &buf, &bufType) == NERR_Success);

    try {
        result = buf;
    }
    __finally {
        ::NetApiBufferFree(buf);
    }

    return result;
}

或者,您可以编写遵循RAII语义的自定义class / struct

template <typename T>
class NetApiBuffer
{
private:
    T* m_buf;

    NetApiBuffer(const NetApiBuffer &) {}
    NetApiBuffer& operator=(const NetApiBuffer &) { return *this; }

public:    
    NetApiBuffer(T *buf = 0) : m_buf(buf) {}

    ~NetApiBuffer() {
        ::NetApiBufferFree(m_buf);
    }

    operator T*() { return m_buf; }
    T** operator&() { return &m_buf; }
};

std::wstring GetNetStatus()
{
    NETSETUP_JOIN_STATUS bufType;
    ::ZeroMemory(&bufType, sizeof(NETSETUP_JOIN_STATUS));

    NetApiBuffer<WCHAR> buf;
    CHECK_OS_ERROR(::NetGetJoinInformation(nullptr, &buf, &bufType) == NERR_Success);

    return std::wstring(buf);
}

或者,如果您使用的是C ++ 11或更高版本,则可以将std::unique_ptr与自定义删除器一起使用:

std::wstring GetNetStatus()
{
    NETSETUP_JOIN_STATUS bufType;
    ::ZeroMemory(&bufType, sizeof(NETSETUP_JOIN_STATUS));

    LPWSTR buf;
    CHECK_OS_ERROR(::NetGetJoinInformation(nullptr, &buf, &bufType) == NERR_Success);

    std::unique_ptr<WCHAR, decltype(&::NetApiBufferFree)> deleter(buf, &::NetApiBufferFree);
    return std::wstring(buf);
}

答案 1 :(得分:0)

使用原始C样式字符串指针构建std::wstring后,wstring对象深层复制输入原始指针指向的字符串,所以你是安全地将wstring对象返回给调用者。

您可以采取哪些措施来提高代码质量,将显式字符串内存释放调用替换为NetApiBufferFree,并使用安全的RAII包装,例如使用std::unique_ptr自定义删除,例如:

// LPWSTR buf;
// ... 
//  
// ::NetApiBufferFree(buf);

auto deleter = [](void* ptr) { ::NetApiBufferFree(ptr); };
std::unique_ptr<wchar_t, decltype(deleter)> autoDelete(buf, deleter);

您的整个功能代码可以像这样调整:

std::wstring GetNetStatus() 
{
    NETSETUP_JOIN_STATUS bufType;
    ::ZeroMemory(&bufType, sizeof(NETSETUP_JOIN_STATUS));

    LPWSTR buf = nullptr;
    CHECK_OS_ERROR(::NetGetJoinInformation(nullptr, &buf, &bufType) == NERR_Success);

    // Safe RAII wrapper around NetApiBufferFree()
    auto deleter = [](void* ptr) { ::NetApiBufferFree(ptr); };
    std::unique_ptr<wchar_t, decltype(deleter)> autoDelete(buf, deleter);

    return std::wstring(buf);

// NetApiBufferFree() *automatically* invoked at function exit
}