std::memcpy vs std::copy_n for legacy c structs
std::memcpy vs std::copy_n for legacy c structs
在处理遗留C
代码时,我需要读取并复制C样式结构的内存位置。 给定指向结构的指针,我应该更好地使用 C 样式std::memcpy
还是C++std::copy_n
?还是等价的?
举一个具体但微不足道的例子:
#include <cstring>
#include <algorithm>
struct Ctype {
double x;
int a;
};
int main()
{
Ctype a{1, 2};
auto p = &a;
auto buffer = reinterpret_cast<decltype(p)>(::operator new(sizeof(a)));
// Are the two following equivalent and both well-defined?
std::memcpy(buffer, p, sizeof(a));
std::copy_n(p, 1, buffer);
Ctype b{3, 4};
// Are the two following equivalent and both well-defined?
std::memcpy(&b, buffer, sizeof(b));
std::copy_n(buffer, 1, &b);
delete buffer;
return 0;
}
这个问题出现在序列化 C 结构的上下文中。在具体情况下,我不知道 C 库中定义的Ctype
的内容。
一些澄清
这个例子可能过于简化,显然可以简单地使用b=*buffer
。 但是,我想到的是,buffer
可以从外部提供,例如,它可以是从磁盘读取的数据序列。然后我需要主动将缓冲区复制到 b 中。
加法
这是一个更接近我的想法的例子。它使用zlib
库从磁盘写入/读取:zlib 函数gzread
和gzwrite
接受指向内存缓冲区的void *
指针进行读/写。
#include <cstring>
#include <algorithm>
#include <fstream>
extern "C" {
#include <zlib.h>
}
struct Ctype {
double x;
int a;
};
int main()
{
Ctype a{1, 2};
auto p = &a;
auto buffer = ::operator new(sizeof(a));
// Are the two following equivalent and both well-defined?
std::memcpy(buffer, p, sizeof(a));
std::copy_n(p, 1, static_cast<Ctype *>(buffer));
// Saving the files
gzFile f = gzopen("conf.dat", "w");
gzwrite(f, buffer, sizeof(a));
gzclose(f);
Ctype b{3, 4};
// Reading file
f = gzopen("conf.dat", "r");
gzread(f, buffer, sizeof(a));
gzclose(f);
// Are the two following equivalent and both well-defined?
std::memcpy(&b, buffer, sizeof(b));
std::copy_n(static_cast<Ctype *>(buffer), 1, &b);
operator delete(buffer);
return 0;
}
std::copy_n
是一个执行复制操作的模板函数。对于平凡可复制的类型(C 样式结构都应该是平凡可复制的(,它与memcpy
相同 - 并且应该具有相同的性能。
此外,与std::copy_n
不同,memcpy
不适合不可复制的类型。
当您尝试复制到不包含对象的存储中时,第一个代码不正确。 Memcpy 和 copy_n 只能更新现有对象,它们不能在空闲存储中创建对象。一个简单的解决方法是编写写auto buffer = new Ctype;
(尽管如果您必须使用动态分配,我建议使用容器进行内存管理(。
修复此问题后,您的两个方法对于 C 样式结构(即其定义在 C 中语法有效的结构(都是等效的。这些是 C++ 中简单可复制类型的子集。 因此,使用哪种风格是风格问题;我更喜欢写:
b = *buffer;
这似乎比函数调用语法更清晰。 memcpy 版本的一个问题是,在未来代码将结构更改为不再可复制的情况下,它不会是健壮的。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用一个考虑到std::map中键值的滚动或换行的键
- 如何从 std::atomic 中提取指针 T<T>?
- 为什么 std::unique 不调用 std::sort?
- 使用std::函数映射对象方法
- std::memcpy vs std::copy_n for legacy c structs