Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best pattern to return dynamically allocated buffer from a function in C++?

I'm in the process of refactoring some old code. There's a C style function that works like this: (Obviously I've simplified it here)

int LoadData(char** buf1, int* buf1Len, char** buf2, int* buf2Len) {
    *buf1Len = DetermineLength1();
    *buf1 = (char*)malloc(*buf1Len);
    // Fill buf1
    *buf2Len = DetermineLength2();
    *buf2 = (char*)malloc(*buf2Len);
    // Fill buf2
    int result = 0; // Or some other INT depending of result
    return result;
}

Now, I'd like to update this code to somehow return a unique_ptr or equivalent, so the pointer will be automatically managed by the caller, and the caller won't ever forget to free the memory.

I couldn't find a good solution, so currently I've changed the code to the following:

int LoadData(std::unique_ptr<char[]>* ubuf1, int* buf1Len, std::unique_ptr<char[]>* ubuf2, int* buf2Len) {
    // same code as above, and finally:
    ubuf1->reset(buf1);
    ubuf2->reset(buf2);
    return result;
}

This doesn't look good, so I'm looking to see if there's a better solution. Since I'm returning two buffers, using the unique_ptr as the return value is not an option.

Is there any better way for this?

like image 614
ShayanOH Avatar asked Dec 18 '22 07:12

ShayanOH


1 Answers

Don't use std::unique_ptr for arrays if you don't have to. The proper tool for storing dynamic arrays is usually std::vector. It packs the size information right along with the object, where it belongs. If your char* are being used as strings, then you might want to use std::string instead.

std::pair<std::vector<char>, std::vector<char>>
LoadData()
{
    std::vector<char> buf1(DetermineLength1());
    // Fill buf1

    std::vector<char> buf2(DetermineLength2());
    // Fill buf2

    return { std::move(buf1), std::move(buf2) };
}

If you still need your int return result, then you can change the function to return std::tuple<int, std::vector<char>, std::vector<char>>. Or better yet, create a struct with meaningful names for the members.

like image 58
Benjamin Lindley Avatar answered Dec 24 '22 03:12

Benjamin Lindley