definename definename - 28 days ago 8
C++ Question

How to correctly return pointer from function

I have the following function:

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;
}


I need to return an
LPWSTR
value but according to the API I'm using, I need to free this pointer before I leave the function scope.

Is it correct to assign an
LPWSTR
value to the STL string and return it or are there some other tricks?

Answer Source

What you have shown is technically correct.

However, just be aware that when the std::wstring copies the character data from buf, it has the potential to throw an exception, so you should be prepared to handle that to avoid any possible memory leak.

You could use a __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;
}

Or, you could write a custom class/struct that follows RAII semantics:

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);
}

Or, if you are using C++11 or later, you can use std::unique_ptr with a custom deleter:

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);
}