在C++中,从函数返回动态分配的缓冲区的最佳模式是什么?

4

我正在重构一些旧代码。有一个类似于 C 语言函数的函数,它的工作方式如下:(显然,这里进行了简化)

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

现在,我想将这个代码更新为返回unique_ptr或等效的内容,这样指针将由调用者自动管理,而调用者永远不会忘记释放内存。

我找不到一个好的解决方案,所以目前我已经将代码更改如下:

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

这看起来不太好,所以我正在寻找更好的解决方案。由于我返回了两个缓冲区,使用 unique_ptr 作为返回值不是一个选项。

有没有更好的方法?


2
你为什么不能使用 std::vector<char> 来代替 buf1buf2?通过引用传递给 LoadData,然后可以根据需要调用 resize - G.M.
1个回答

11

如果不必要,不要使用std::unique_ptr来存储数组。存储动态数组的正确工具通常是std::vector。它将大小信息与对象一起打包,这正是它所属的位置。如果您的char*正在用作字符串,则可能要改用std::string

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

如果你仍需要返回一个int类型的结果,那么你可以将函数改为返回std::tuple<int, std::vector<char>, std::vector<char>>。或者更好的方法是,创建一个具有有意义的成员名称的结构体。


为什么你说“如果没有必要,不要在数组中使用std::unique_ptr。”?这里不使用unique_ptr的原因是什么? - Nabi
1
@Nabi: 数组的大小是数组的内在属性。使用unique_ptr需要你单独存储大小。这很容易出错。你认为unique_ptr相对于vector有哪些优势? - Benjamin Lindley
@Benjamin_lindley:是的,你说得对。但是使用向量来存储字符数组缓冲区需要更多的内存,并且其可访问性比char *、unique_ptr或std::string慢。我相信对于字符数组缓冲区,最好的解决方案是使用std::string及其data()函数,但我不喜欢它的名称(字符串),因为它的数据将是一些二进制字节。 - Nabi
1
@Nabi 我不太确定 vector 会更慢。看看这个链接: https://dev59.com/dHE85IYBdhLWcg3w9onw
性能差异可能是可以忽略的或者没有(编译器可能会将它们优化为相同)。
- Liran Funaro
@LiranFunaro:不,那个链接与这个比较无关。在某些情况下,char数组的使用速度非常快,例如批量复制。 - Nabi
@BenjaminLindley和@LiranFunaro,是的,你们说得对!现在我认为最好的解决方案是使用向量,它的性能将与char *相同。谢谢! - Nabi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接