c++ - 使用 Lambda 解包可变参数时增加指针
问题描述
我有以下代码,它有一个函数VariadicWrite
,这个函数接受一个指针,它可以通过增加它来修改它指向不同的内存位置,具体取决于写入它的数据量:
#include <iostream>
#include <cstring>
template<typename T>
T Read(void* &ptr) noexcept
{
T result;
memcpy(&result, ptr, sizeof(result));
ptr = static_cast<T*>(ptr) + 1;
return result;
}
template<typename T>
void Write(void* &ptr, T result) noexcept
{
memcpy(ptr, &result, sizeof(result));
ptr = static_cast<T*>(ptr) + 1;
}
template<typename... Args>
auto VariadicWrite(void*& ptr, Args&&... args)
{
(Write(ptr, args), ...); //unpack Args
return 0;
}
int main()
{
void* ptr = malloc(1024);
memset(ptr, 0, 1024);
void* temp = ptr;
VariadicWrite(ptr, 1, 2, 3);
std::cout<<Read<int>(ptr)<<"\n";
std::cout<<Read<int>(ptr)<<"\n";
std::cout<<Read<int>(ptr)<<"\n";
free(temp);
return 0;
}
0, 0, 0, 0
这里的问题是如果我使用代码会打印出来: void*& ptr
。如果我这样做void* ptr
,它会打印出来,0, 1, 2, 3
但ptr
指针永远不会增加。
如何修改 的ptr
指针VariadicWrite
?我认为这void*&
会奏效,但在这种情况下它不会:S
解决方案
问题是您的VariadicWrite()
调用将修改ptr
为指向您写入数据的结尾。然后,您Read()
无需将指针重置回起点即可调用,因此您从缓冲区的未初始化部分读取零,该部分位于已写入数据之后。
ptr = temp;
在写入和读取之间插入,看看是否可以修复它。
void* ptr
不起作用的原因是每次调用Write(ptr, ...)
都会在函数范围内增加参数的本地副本Write()
。调用后变量ptr
inVariadicWrite()
不会改变,Write()
因此下一次调用将使用相同的值。
如果您更改为VariadicWrite(void* ptr, …)
and Write(void*& ptr, …)
,您可能会得到您想要的行为。但我建议这是一个坏主意。
正如我们从您的示例中的错误中看到的那样,知道函数是否会修改传递引用参数至关重要,但从使用该函数的代码中并不明显。这往往会招致错误,就像您在此处创建的错误一样。一个不一致的接口,VariadicWrite()
不修改它的参数而是修改Write()
,只会使避免这种错误变得更加困难。
通常,最好避免非常量引用,因为它们通常会导致这样的错误。我建议返回新指针而不是修改参数。
template<typename T>
void* Write(void* ptr, const T& arg)
{
return static_cast<T*>(ptr) + 1;
}
template<typename... Args>
void* WriteV(void* ptr, Args&&... args)
{
((ptr = Write(ptr, args)), ...);
return ptr;
}
推荐阅读
- stm32 - 计时器作为毫秒计数器
- c# - 使用路由在 QueryParameters 中传递字典
- python - 从python中的另一个文件夹导入文件
- ios - ProgressView 未在 iOS 中更新
- jenkins - 无法使用最新的 jenkins 版本运行 groovy 脚本
- kotlin - 如何在 Kotiln Volley JsonObjectRequest 类中覆盖?
- dynamics-crm - 是否可以在动态 365 UI 上添加动画或视觉指示器?
- angular - 角 p 手风琴标签有时不打开
- excel - 如何在microsoft excel中复制行并使第一行为负数,第二行为正数
- ruby - Rails:表单助手如何将此下拉选择转换为单选按钮列表