【问题标题】:Standard replacement for QByteArrayQByteArray 的标准替换
【发布时间】:2017-04-08 01:30:57
【问题描述】:

我想将 Qt C++11 函数移植到标准 C++11。该函数有一个QByteArray 参数,它接受任何类型的数据(文本、二进制数据等)并根据数据计算哈希值。

QByteArray 似乎非常适合,因为它可以携带任何类型的数据,并且具有许多允许从流、设备、字符串等中填充数据的功能。它甚至可以包装数据而无需使用fromRawData().

是否有提供类似灵活性的标准 C++11 解决方案?目前我倾向于使用旧的void* plus size。

【问题讨论】:

  • 几乎任何STL container 都可以存储(无符号)字符数组。
  • @Silicomancer 如果您不想要深拷贝,请使用指针和大小。你已经有了它们。大多数标准库操作都在 iterator 范围内工作,因此将ptr, ptr+size 作为范围传递是很常见的。更直接地说,没有什么能与 QByteArray 提供的功能广度相媲美。其中大部分都需要您实现该行为。
  • @RawN ... 在该范围内进行值复制。 OP 提到的具体方法是fromRawData,除非您遇到严重的 std::allocator 重载(坦率地说,这不值得麻烦),否则没有类似的方法可以通过 vector 使用。跨度>
  • std::vector<uint8_t> 在我看来是QByteArray 的明显替代品,如果您只想要一个可以容纳任意二进制数据的容器..
  • 希望我们得到std::array_view,这在这种情况下会很好用。现在我认为你可以将它作为核心指南库的一部分。

标签: c++ qt c++11 qbytearray


【解决方案1】:

是否有提供类似灵活性的标准 C++11 解决方案?目前我倾向于使用旧的 void* plus size。

没有标准的 C++11 解决方案可以提供既可以管理自己的内存也可以包装由其他人管理的内存的容器。

如果许可条款允许,您可以简单地复制 QByteArray(这是几个文件)并将其与您的项目捆绑在一起。

否则,如果您只打算处理所有元素的连续存储容器,const void*size_t 参数非常有意义,并且将是最便携和适应性最强的。您可以根据需要提供便利的重载。例如

HashType calculateHash(const void*, size_t);

template <typename T> HashType calculateHash(const T& container) {
  static_assert(sizeof(typename T::value_type) == 1, "value_type must be byte-sized");
  assert(&container[container.size()-1] == &container[0]+container.size());
  return calculateHash(&container[0], container.size());
}

为了支持任何容器,即使是那些具有非连续存储的容器,基础calculateHash 可以采用一个范围,并为散列整个容器提供重载。

template <typename I>
HashType calculateHash(I start, I const end) {
  HashType hash;
  for (; start != end; ++start)
    hash.update(*start);
  return hash;
}

template <typename C>
HashType calculateHash(const C& container) {
  using std::begin;
  using std::end;
  return calculateHash(begin(container), end(container));
}

【讨论】:

    【解决方案2】:

    我不知道这种具有与 QByteArray 相同的复杂功能的标准容器,但我会从 std::vector&lt; char &gt; 开始,并使用缺少的和必要的功能实现一个包装器。

    std::vector 具有很高的灵活性,您可以在恒定时间内访问每个元素,并且可以轻松地将其转换为 std::string(例如Converting a vector to string)。

    如果 insert 操作更重要,也许你可以试试std::list&lt; char &gt;。主要是链表实现。

    根据 Jesper Juhl 的评论:使用 uint8_t 作为模板参数将描述真正的 字节数组 行为。

    【讨论】:

    • 但它是否支持包装数据而不进行深拷贝?如果不是,我无法想象这样的包装器是如何做到的。
    • 使用迭代器或运算符[],您可以访问元素而无需深拷贝。
    • @TiborTakács 他的意思是模仿fromRawData 功能的能力。
    • 不是一个非常普遍的用例,但使用特殊的分配器对象,理论上你可以做到。 en.cppreference.com/w/cpp/concept/Allocator
    • char 将是向量的错误模板参数,因为您不知道它是跨实现签名还是未签名(C++ 中有 3 字符类型; charunsigned charsigned char,它们都是类型系统的不同类型,char 的签名是实现定义的(是的,这 已经 咬了我))。最好具体一点,在这种情况下使用uint8_t(恕我直言)。
    【解决方案3】:

    不是很标准,但您可以使用Guideline Support Library 中的view/span 类(最终应该会进入标准)来模拟fromRawData

    当然,这不涉及与共享所有权相关的生命周期问题,但在您的情况下可能就足够了。

    此外,虽然它可能不是所有组件的要求,但 GSL 被宣传为基于 C++14。

    【讨论】:

      猜你喜欢
      • 2017-01-20
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 2014-12-06
      • 1970-01-01
      • 1970-01-01
      • 2014-12-22
      • 2014-12-10
      相关资源
      最近更新 更多