【问题标题】:What is the correct way to deal with medium-sized byte arrays in modern C++?在现代 C++ 中处理中型字节数组的正确方法是什么?
【发布时间】:2012-04-09 18:19:47
【问题描述】:

许多语言和框架都提供“字节数组”类型,但 C++ 标准库没有。什么类型适合用于中等大小的1、可调整大小的字节数组,如何有效地使用该类型? (特别是:分配、作为参数传递和销毁)


1:中型是指小于 100 MB。

【问题讨论】:

  • 你需要什么(例如)std::vector<uint8_t> 不提供的东西?
  • std::arrayvector
  • void f(const std::vector &vec);
  • 您可以在不复制内容的情况下将引用或指针(或智能指针)传递给向量。
  • 如果你使用移动语义,那么你可以避免任何额外的向量复制。

标签: c++ c++11


【解决方案1】:

您可以使用std::vector<unsigned char>,或@Oli 建议的std::vector<uint8_t>。是的,您可以绕过它,而无需复制全部内容。

void f(std::vector<unsigned char> & byteArray) //pass by reference : no copy!
{
     //
}

std::vector<unsigned char>  byteArray;
//...
f(byteArray); //no copying is being made!

【讨论】:

  • 返回一个字节数组怎么样?
  • @Tamás : (N)RVO 使这不是问题。
  • 不根据(错误)假设挑剔怎么样?我问这个问题是为了学习,而不是为了特定的程序。请有礼貌。
【解决方案2】:

许多语言和框架都提供“字节数组”类型,但 C++ 标准库没有。

你错了,C++有一个字节数组类型:std::vector&lt;unsigned char&gt;,它的存储保证是连续的(如果你不需要这个条件,还有其他的选择)。您可能想了解引用、移动语义、返回值优化和复制省略以了解如何有效地处理这些内容。

注意:在 C++ 中,一个字节是 char(有符号或无符号)。它可能不是 8 位长,您可以通过 CHAR_BITS 宏获取其大小。

【讨论】:

  • 请注意,char 并不是真正可靠的 byte,因为它是有符号或无符号 IIRC。
  • @D.Shawley:是的,你不知道它是签名还是未签名。如果你想把数字理解为模 2^n 的东西,最好让它无符号。
【解决方案3】:

我建议使用std::deque&lt;uint8_t&gt; 而不是std::vector&lt;uint8_t&gt;,因为后者需要连续的内存块。我会避免使用new 分配大块内存,因为它会使用默认构造函数初始化内存块,这可能比您想要的要贵一些。

在紧要关头,我相信您可以使用自定义解除分配器自定义boost::shared_ptr,这样您就可以使用std::malloc 进行分配,避免初始化开销并使用std::free 解除分配,同时仍然保持shared_ptr 带来的好处桌子。

【讨论】:

  • "我会避免使用 new 分配大块内存,因为它会使用默认构造函数初始化内存块,这可能比你想要的要贵一点。" 如果您在谈论原始 C 数组,则数据是否已初始化取决于使用默认初始化还是值初始化(即 new unsigned char[num]new unsigned char[num]())。前者保证初始化内存,后者是。 malloc 绝不是一个好的建议。
  • IIRC, std::vector 使用初始化版本。这可能并不重要,但选项的性能存在很大差异。例如,分配 100,000,000 vector 需要 177 毫秒,而 new 进行初始化需要 253 毫秒,不进行初始化需要 0.051 毫秒,malloc 需要 0.030 毫秒。我在使用 std::vector 处理较大的协议缓冲区时遇到了这个问题。
  • std::vector&lt;&gt; 根本不使用new,它使用您指定的分配器作为第二个模板参数。没错,如果使用 resize 或采用大小的构造函数,它将初始化元素,但这就是 reserve 的用途。 :-]
【解决方案4】:

vector&lt;char&gt; 应该适合您的目的。如果您希望共享版本避免复制,可以使用以下内容:

typedef shared_ptr<vector<uint8_t>> ByteArray;

如果您在编译时知道大小,则可以使用array,这样会更节省空间。

string 也可以处理可能比向量更合适的空字符。

一些扩展实现有绳子实现http://en.wikipedia.org/wiki/Ropehttp://www.aoc.nrao.edu/php/tjuerges/ALMA/STL/html-3.4.6/rope.html,这可能更合适。

【讨论】:

  • 实现共享std::vector&lt;&gt; 内容是否合法?我知道std::string 有特殊权限,但有known problems with COW semantics for strings。你怎么知道“大多数实现”实际上实现了这一点?
  • @AndréCaron:我以为我在 gcc 和 msvc 中看到了它。等一下,我会检查(至少 gcc)。
  • @AndréCaron: std::string 是 gcc 4.7 上的 COW。检查向量。
  • @AndréCaron:好的向量复制构造函数调用 uninitialized_copy_a。一定是记错了。将更新答案。
【解决方案5】:

使用 unique_ptr 有性能原因,至少对于相对较大的缓冲区。详情请见https://stackoverflow.com/a/35798248/1992615

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 2020-01-20
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    相关资源
    最近更新 更多