[英]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");
但是,我遇到了一個問題。 我把它架在這種方式的Run
功能,在鈎命名空間,調用CHookData_t結構的運行功能,需要通過對可變參數。 我找不到任何其他方式。 結果是這樣的:
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;
}
我不知道Hook::Run
參數是什么va_list
指向什么,所以我不能提供很好的 C++ 解決方案。
請注意,循環內部需要va_copy
,因為某些編譯器(不記得是哪個,可能是 msvc) va_list
行為就像一個指針,從中讀取參數將對每次迭代產生影響。 在其他編譯器上va_list
行為就像一個值,而va_copy
不會改變任何東西。
offtopic :您的代碼太多 C,如果您使用的是 C++17,則不應使用const char*
而是std::string
或std::string_view
,而va_args
最好使用可變參數模板或std::initializer_list
,避免使用原始指針,支持std::unique_ptr
和std::shared_ptr
。 我已經稍微調整了您的代碼以涵蓋這一點。
此外Hook
不應該是一個namespace
,從它包含的函數和變量的外觀來看,它應該是一個類,所以你也應該修復它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.