将给定的 vararg 参数传递给另一个函数的适当方法是什么?
What is the appropriate way to pass given vararg parameter to another function?
我已经开始在C++中研究钩子/事件系统。该系统应该处理应用程序其他部分通知的各种事件。
我面临的问题是我希望它运行的方式。 通常,我希望它能够使用您希望传递的所有参数调用特定函数,然后该函数处理调用该特定事件的所有注册钩子,将它们传递给参数,检索它们的结果值并将其返回给原始调用者。
一般来说,它应该是这样的:
CHookReturn* bInitializationStatus = Hook::Run("Initialize", gGame);
CHookReturn* bThinkSuccessful = Hook::Run("Think");
但是,我遇到了一个问题。 我以这样的方式设置它,即 Hook 命名空间中的Run
函数调用 CHookData_t 结构的 Run 函数,需要传递 varargs。我找不到任何其他方法。结果是这样的:
union CHookReturn
{
const char* m_pszValue;
int m_iValue;
float m_flValue;
double m_dlValue;
bool m_bValue;
};
struct CHookData_t
{
virtual void Run(CHookReturn* ret, ...) = 0;
};
namespace Hook
{
std::unordered_map<const char*, std::unordered_map<const char*, CHookData_t*>> umHookList;
bool Add(const char*, const char*, CHookData_t*);
bool Exists(const char*, const char*);
bool Remove(const char*, const char*);
int Count(const char*);
CHookReturn* Run(const char*, ...);
};
Hook::Run 函数的 CPP 文件段:
CHookReturn* Hook::Run(const char* eventName, ...)
{
// FIXME: Look into alternative execution.
// This code seems more like a workaround
// than what I originally wanted it to be.
int count = Hook::Count(eventName);
CHookReturn* returnValues = new CHookReturn[count];
int c = 0;
unordered_map<const char*, CHookData_t*>::iterator itr;
unordered_map<const char*, CHookData_t*> res;
res = umHookList.at(eventName);
va_list valist;
void* args;
va_copy(args, valist);
for (itr = res.begin(); itr != res.end(); itr++)
{
CHookReturn returnData;
itr->second->Run(&returnData, args);
returnValues[c] = returnData;
++c;
}
return returnValues;
}
上面的代码提出了两个警告,让我质疑以这种方式执行它是否是一个好主意,以及我是否应该研究任何替代方案。
我收到的警告是:Warning C6001 Using uninitialized memory 'valist'.
Warning C6386 Buffer overrun while writing to 'returnValues': the writable size is 'count*8' bytes, but '16' bytes might be written.
有没有更好的方法可以做到这一点?
使用va_list
修复代码:
struct CHookData_t
{
virtual ~CHookData_t() {}
virtual void Run(CHookReturn* ret, va_list arg) = 0;
};
namespace Hook
{
using HooksList = std::unordered_map<
std::string,
std::unordered_map<std::string, std::unique_ptr<CHookData_t>>;
HooksList umHookList;
...
}
std::vector<CHookReturn> Hook::Run(const std::string& eventName, ....)
{
va_list valist;
va_start(valist, eventName);
auto result = Hook::RunVarg(eventName, valist);
va_end(valist);
return result;
}
std::vector<CHookReturn> Hook::RunVarg(const std::string& eventName, va_list arg)
{
int count = Hook::Count(eventName);
std::vector<CHookReturn> returnValues(count);
size_t c = 0;
for (auto& item : umHookList.at(eventName))
{
va_list arg_copy;
va_copy(arg_copy, arg);
item.second->Run(&returnValues[c], arg_copy);
va_end(arg_copy);
++c;
}
return returnValues;
}
我不知道va_list
指向Hook::Run
的论据是什么,所以我不能提供很好的C++解决方案。
请注意,循环内部需要va_copy
,因为某些编译器(不记得哪个,可能是 msvc)va_list
的行为类似于指针,从中读取参数将对每次迭代产生影响。在其他编译器上,va_list
的行为类似于值,并且va_copy
不会更改任何内容。
题外话:你的代码是C,你不应该使用const char*
,而应该使用std::string
或std::string_view
如果你使用的是C++17,而不是va_args
最好使用可变参数模板或std::initializer_list
,避免使用原始指针以支持std::unique_ptr
和std::shared_ptr
。我已经稍微调整了您的代码以涵盖这一点。
此外,Hook
不应该是一个namespace
,从它包含的函数和变量的外观来看,它应该是一个类,所以你也应该修复它。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 将一系列整数放入类的最佳方法是什么?
- 从长整整转换为uint64_t的推荐方法是什么?
- 将此布尔值传递给此函数的最有效方法是什么?
- 通过比较C++中的行在 txt 文件中搜索的最简单方法是什么?