Кто-нибудь знает, как я могу вызвать свой метод и передать необходимый аргумент
Я пытался вызвать метод следующим образом:
start_thread (Loop, (void *) &track);
То, что вы пыталисьсработает, если Loop
преобразует указатель void обратно в track_t*
и при условии, что указанный track
объект остается в живых до тех пор, пока он больше не используется.
Приведение к void*
в вашем примере не нужнотем не менее, поскольку все указатели объектов неявно преобразуются в void*
.
Как можно безопасно передать ... void *
Невозможносделать функцию, которая принимает void*
безопасной. Он по своей природе небезопасен.
Что вы можете сделать, так это написать шаблон-оболочку, которая безопасна для типов и которая не требует непосредственного вызова start_thread
. Пример:
template<class T>
using fun_t = T*(T*);
template<auto fun_ptr, class T>
void start_thread_safer(T* params)
{
auto callback = [](void* vparams) -> void* {
return fun_ptr(static_cast<T*>(vparams));
};
start_thread(callback, params);
}
Теперь вы можете безопасно печатать:
track_t* Loop (track_t* params);
start_thread_safer<Loop>(&track);
Существует оптимизация, позволяющая избежать косвенного обращения: поскольку unsigned char
гарантированно подходитв памяти void*
вы можете передать объект в эту память напрямую. С целыми числами (такими как unsigned char
) это просто:
str::uintptr_t temp = track;
start_thread (Loop, reinterpret_cast<void*>(temp));
// in Loop
track_t track = reinterpret_cast<str::uintptr_t>(params);
Если переданный тип не является целым числом, но легко копируется и вписывается в указатель, также работает следующее:
void* params = nullptr;
static_assert(sizeof params >= sizeof track);
std::memcpy(¶ms, &track, sizeof track);
start_thread (Loop, params);
// in Loop
track_t track;
std::memcpy(&track, ¶ms, sizeof track);
Эта оптимизация также повышает безопасность, поскольку больше нет косвенного обращения, и, таким образом, вы больше не можете не поддерживать указанный параметр живым до его использования.
Я оставлю это как упражнениеобъединить эти подходы.