0

My program creates a thread but I'm getting a "Don't use C-style casts" in my code analysis with Visual Studio.

#include <windows.h>
#include <process.h>
#include <iostream>

void myThread(void * threadParams)
{
int* x = (int*)threadParams;
std::cout << "*x: " << *x;
}

int main()
{
BOOL bValue2 = TRUE;
_beginthread(myThread, 0, (LPVOID)&bValue2);
Sleep(10000);
}

I tried static_cast<LPVOID>&bValue2 but it gives an error.

What is the proper format for casting in _beginthread?

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
JeffR
  • 765
  • 2
  • 8
  • 23
  • 2
    Use std::thread (or std::async) and pass your function using a lambda expression – Pepijn Kramer Jun 29 '23 at 11:02
  • 4
    Any reason you're not using [`std::thread`](https://en.cppreference.com/w/cpp/thread/thread)? – G.M. Jun 29 '23 at 11:02
  • 1
    Did you mean to type `static_cast(&bValue2)`? – Nelfeal Jun 29 '23 at 11:03
  • 1
    I concur that you should use ``std::thread``, but if for some reason you can't, you can always do ``static_cast(&bValue2);`` and ``BOOL* x = static_cast(threadParams);``. (Although ``BOOL`` ist technically an alias for ``int`` in WinAPI, please use ``BOOL`` in the thread handler as well, just to make it clear that you are *not* doing some sort of type punning here.) – chris_se Jun 29 '23 at 11:06
  • 1
    Also, if you are passing a pointer to a stack variable into the thread, you need to be absolutely sure that your thread ends **before** the stack variables leaves the current scope, otherwise you have really hard to debug undefined behavior. If you just want to pass an integer value into the thread, you could always ``reinterpret_cast`` the value to the pointer (and use the ptr as a value), i.e. ``_beginthread(myThread, 0, reinterpret_cast(static_cast(bValue2)));`` and then ``BOOL value = static_cast(reinterpret_cast(threadParam));`` in the thread. – chris_se Jun 29 '23 at 11:10
  • @chris_se How would I pass a `wchar_t` to the thread using `static_cast`? – JeffR Jul 07 '23 at 12:14
  • 1
    Do you want to pass a `wchar_t` or a `wchar_t*` string? For a simple `wchar_t` you can also use the same `static_cast`/`reinterpret_cast` logic I used for the `BOOL` case (since `wchar_t` is 16 bit on Win32, which is smaller than `std::intptr_t`), but if you actually want to pass a full string, then you have to think about the lifetime of the string. For hard-coded strings you can do `wchar_t const* str = L"Hello World";` and then `_beginThread(myThread, 0, const_cast(str));` and in the thread `wchar_t const* str = static_cast(threadParam);`. – chris_se Jul 07 '23 at 12:55
  • 1
    But if you want to do dynamic strings, then you have to care about the lifetime of the string, and then it gets complicated. But regardless of what you actually want to pass, I would **really**, **strongly** recommend that you use `std::thread` as described in the answer, because then C++ does all the heavy lifting for you. (`std::thread` uses `_beginthread()` or `_beginthreadex()` internally on Windows anyway...) – chris_se Jul 07 '23 at 12:58

1 Answers1

3

Here is an example :

// no need to inlcude OS specific headers
// thread support is in since C++11
// https://en.cppreference.com/w/cpp/thread/thread
// https://en.cppreference.com/w/cpp/language/lambda

#include <thread>
#include <string>
#include <iostream>

void my_thread_function(const std::string& hello, int x)
{
    std::cout << hello << "\n";
    std::cout << x << "\n";
}

int main()
{
    int x{ 42 };
    std::string hello{ "hello world" };

    std::thread thread{ [=] { my_thread_function(hello, x); } }; // [=] capture x and hello by value 
    thread.join(); // wait for thread to complete (no need to sleep);

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
  • How would I pass a HANDLE (Windows specific) using `std::thread`? – JeffR Jun 29 '23 at 12:24
  • Just like any other variable. But be aware read the documentation of the windows API carefully not all functions are threadsafe. For example : [are win32 windows threadsafe?](https://stackoverflow.com/questions/7489175/are-win32-windows-thread-safe) – Pepijn Kramer Jun 29 '23 at 13:37
  • There's no need for a lambda here at all. The function is already declared, and implemented, why bother wrapping it again? Could also be worth mentioning C++20's RAII-capable `std::jthread`. – sweenish Jun 29 '23 at 13:58
  • You are right, not necessary in this case. The lamda is necessary when called from another function then main to capture values by value (safest option for threads when starting with threads). Pre C++20 I usually use std::async and use the RAII future to join/synchronize for (and even get some data back if needed). – Pepijn Kramer Jun 29 '23 at 14:02