Rog*_*and 50 c++ std stdvector
我有一个应用程序正在对某些图像执行某些处理.
鉴于我知道宽度/高度/格式等(我这样做),并考虑定义一个缓冲区来存储像素数据:
然后,而不是使用new
与delete []
上unsigned char*
并保持一个单独的说明缓冲区大小的,我想通过使用简化的事情std::vector
.
所以我会宣布我的课程是这样的:
#include <vector>
class MyClass
{
// ... etc. ...
public:
virtual void OnImageReceived(unsigned char *pPixels,
unsigned int uPixelCount);
private:
std::vector<unsigned char> m_pImageBuffer; // buffer for 8-bit pixels
// ... etc. ...
};
Run Code Online (Sandbox Code Playgroud)
然后,当我收到一个新图像(一些可变大小 - 但不要担心这些细节)时,我可以调整矢量大小(如果需要)并复制像素:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
// called when a new image is available
if (m_pImageBuffer.size() != uPixelCount)
{
// resize image buffer
m_pImageBuffer.reserve(uPixelCount);
m_pImageBuffer.resize(uPixelCount, 0);
}
// copy frame to local buffer
memcpy_s(&m_pImageBuffer[0], m_pImageBuffer.size(), pPixels, uPixelCount);
// ... process image etc. ...
}
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很好,我喜欢这个事实,我不必担心内存管理,但它提出了一些问题:
std::vector
还是有更合适的容器?reserve
和 表现来做正确的表演resize
?memcpy_s
,如图?任何其他评论,批评或建议都会非常受欢迎.
Sne*_*tel 35
float
).顺便提一下,memcpy_s
这里不是惯用法.请std::copy
改用.请记住,指针是迭代器.
从C++ 17开始,std::byte
是不透明类型存储的惯用单元,例如您在此处使用.char
当然,仍然可以工作,但允许不安全的用法(如char
!)byte
.
mfo*_*ini 21
除了提到的其他答案,我建议你使用std::vector::assign
而不是std::vector::resize
和memcpy
:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
m_pImageBuffer.assign(pPixels, pPixels + uPixelCount);
}
Run Code Online (Sandbox Code Playgroud)
如果需要,这将调整大小,并且您将避免由此0
引起的不必要的缓冲区初始化std::vector::resize
.
Joh*_*ing 15
vector
在这种情况下使用a 很好.在C++中,存储保证是有余的.
我不会既resize
和reserve
,也不会我memcpy
在复制数据.相反,所有你需要做的是reserve
确保你没有重新分配很多次,然后清除出vector
使用clear
.如果你resize
,它会经历并将每个元素的值设置为默认值 - 这在这里是不必要的,因为你无论如何都要覆盖它.
当您准备复制数据时,请不要使用memcpy
.使用copy
结合back_inserter
到一个空的vector
:
std::copy (pPixels, pPixels + uPixelCount, std::back_inserter(m_pImageBuffer));
Run Code Online (Sandbox Code Playgroud)
我认为这个成语比memcpy
你正在使用的方法更接近规范.可能有更快或更有效的方法,但除非你能证明这是你的代码的瓶颈(它可能不会;你将有更大的鱼在其他地方煎炸)我会坚持使用惯用的方法并离开对别人过早的微观优化.
我会避免将 std::vector 作为存储非结构化缓冲区的容器,因为 std::vector 在用作缓冲区时非常慢
考虑这个 (C++14) 示例(对于 C++11,您可以使用共享而不是唯一的 ptr,但是您会注意到数组示例中的轻微性能下降,您在以下位置运行时不会从向量中获得 - O3 或 -O2):
#include <array>
#include <chrono>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
namespace {
std::unique_ptr<std::array<unsigned char, 4000000>> allocateWithPtr() {
return std::make_unique<std::array<unsigned char, 4000000>>();
}
std::vector<unsigned char> allocateWithVector() {
return std::vector<unsigned char>(4000000);
}
} // namespace
int main() {
auto start = std::chrono::system_clock::now();
for (long i = 0; i < 1000; i++) {
auto myBuff = allocateWithPtr();
}
auto ptr_end = std::chrono::system_clock::now();
for (long i = 0; i < 1000; i++) {
auto myBuff = allocateWithVector();
}
auto vector_end = std::chrono::system_clock::now();
std::cout << "std::unique_ptr = " << (ptr_end - start).count() / 1000.0
<< " ms." << std::endl;
std::cout << "std::vector = " << (vector_end - ptr_end).count() / 1000.0
<< " ms." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
bash % clang++ -O3 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 0 ms.
std::vector = 0 ms
bash % clang++ -O2 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 0 ms.
std::vector = 0 ms.
bash % clang++ -O1 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 89.945 ms.
std::vector = 14135.3 ms.
bash % clang++ -O0 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 80.945 ms.
std::vector = 67521.1 ms.
Run Code Online (Sandbox Code Playgroud)
即使没有写入或重新分配,std::vector 也比在 -O0 处使用带有 unique_ptr 的 new 慢 800 多倍,在 -O1 处慢 150 倍。这里发生了什么?
正如@MartinSchlott 指出的那样,它不是为此任务设计的。向量用于保存一组对象实例,而不是非结构化(从数组的角度来看)缓冲区。对象有析构函数和构造函数。当向量被销毁时,它会为其中的每个元素调用析构函数,甚至向量也会为向量中的每个字符调用析构函数。
您可以通过以下示例查看“销毁”此向量中的无符号字符所需的时间:
#include <chrono>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
std::vector<unsigned char> allocateWithVector() {
return std::vector<unsigned char>(4000000); }
}
int main() {
auto start = std::chrono::system_clock::now();
for (long i = 0; i < 100; i++) {
auto leakThis = new std::vector<unsigned char>(allocateWithVector());
}
auto leak_end = std::chrono::system_clock::now();
for (long i = 0; i < 100; i++) {
auto myBuff = allocateWithVector();
}
auto vector_end = std::chrono::system_clock::now();
std::cout << "leaking vectors: = "
<< (leak_end - start).count() / 1000.0 << " ms." << std::endl;
std::cout << "destroying vectors = "
<< (vector_end - leak_end).count() / 1000.0 << " ms." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
leaking vectors: = 2058.2 ms.
destroying vectors = 3473.72 ms.
real 0m5.579s
user 0m5.427s
sys 0m0.135s
Run Code Online (Sandbox Code Playgroud)
即使去除了vector的破坏,仅仅构建100个这样的东西仍然需要2秒。
如果您不需要动态调整大小或构造和销毁构成缓冲区的元素,请不要使用 std::vector。
归档时间: |
|
查看次数: |
12849 次 |
最近记录: |