【问题标题】:Merge/concatenate unknown amount of byte arrays合并/连接未知数量的字节数组
【发布时间】:2021-04-06 08:48:55
【问题描述】:

我可以使用以下函数合并/合并/连接两个数组,但我如何对其进行修改以支持未知数量的数组。换句话说,一个可变参数函数Args...?

char* concat(char* a, size_t a_size,
             char* b, size_t b_size) {
    char* c = realloc(a, a_size + b_size);
    memcpy(c + a_size, b,  b_size);  // dest is after "a" data, source is b with b_size
    free(b);
    return c;
}

【问题讨论】:

  • 为什么不使用std::string?或std::vector<char>?
  • @KamilCuk,我实际上是在连接std::uint8_t(字节数组)。它们不是字符串。
  • std::vector<uint8_t>?而uint8_t* + size_tstd::span
  • @KamilCuk,我从未使用过 std::span。你想把它写成一个解决方案吗?
  • 这不是一个解决方案 - 不过,您必须自己编写。但是使用单个对象而不是对来管理代码更容易。而且,free(b) - 使用起来更容易std::vector...

标签: c++ variadic


【解决方案1】:

使用spans 和vectors,你可以这样写:

std::vector<std::byte> Concat(std::span<std::byte> a)
{
    return std::vector<std::byte>(a.data(), a.data() + a.size());
}

template<typename... Args>
std::vector<std::byte> Concat(std::span<std::byte> a, Args... args)
{
  auto vec = std::vector<std::byte>(a.data(), a.data() + a.size());
  auto concat = Concat(args...);
  vec.insert(vec.end(), concat.begin(), concat.end());
  
  return vec;
}

请注意,您需要符合 C++20 标准的编译器才能使用 span。支持最新版本的 GCC、Clang 和 MSVC。

【讨论】:

  • (vec.insert(vec.end(), args.begin(), args.end()), ...); 会避免一些分配,并且需要更少的实例化。
【解决方案2】:

我不确定这样的方法是否适合您?我认为这也应该适用于 C++11,如果需要,可以适用于 std::span,我相信。它只分配一次内存,然后将提供给concat 的每个内存块复制到这个分配的块中,无需任何重新分配。

#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <utility>

template <typename T>
size_t concatSize(T* arr, size_t len) {
    return len;
}

template <typename T, typename... Args>
size_t concatSize(T* arr, size_t len, Args... args) {
    return len + concatSize(args...);
}

template <typename T>
void copyMem(T* res, T* arr, size_t len) {
    memcpy(res, arr, len);
}

template <typename T, typename... Args>
void copyMem(T* res, T* arr, size_t len, Args... args) {
    memcpy(res, arr, len);
    copyMem((T*)((char*)res + len), args...);
}

template <typename T, typename... Args>
std::pair<T*, size_t> concat(T* arr, size_t len, Args... args) {
    static_assert(sizeof... (Args)%2 == 0, "Not even number of arguments!");
    auto size = concatSize(arr, len, args...);
    T* result = (T*)malloc(size);
    copyMem(result, arr, len, args...);
    return std::make_pair(result, size);
}

int main() {
    {
        char a[] = {'a', 'b', 'c'};
        char b[] = {'d', 'e', 'f'};
        char c[] = {'g', 'h', 'i'};
        auto result = concat(a, sizeof a, b, sizeof b, c, sizeof c);
        //Don't use regular printf %s since it's not a C-string!
        for(int i = 0; i < result.second; ++i) {
            std::printf("%c ", result.first[i]);
        }
        std::printf("\n");
        free(result.first);
    }
    {
        int a[] = {'1', '2', '3'};
        int b[] = {'4', '5', '6'};
        int c[] = {'7', '8', '9'};
        auto result = concat(a, sizeof( a), b, sizeof( b), c, sizeof( c));
        char* x = (char*)result.first;
        for(int i = 0; i < result.second; ++i) {
            std::printf("%c ", x[i]);
        }
        std::printf("\n");
        free(result.first);       
    }
}

Output:

a b c d e f g h i 
1    2    3    4    5    6    7    8    9  

【讨论】:

    猜你喜欢
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 1970-01-01
    • 2016-08-22
    • 2019-07-10
    • 1970-01-01
    相关资源
    最近更新 更多