I have a class named Window, and a big bunch of functions which need an instance of Window to work. So I have passed Window* win as an argument to each of these functions, but this approach creates a copy of Window* every time it is called and also, it seems kinda unnecessary passing the argument to each function. I have tried passing const Window* but that won't work either because the functions inside Window don't have a const version. I thought that using std:::shared_ptr and std::weak_ptr would help, but I still haven't figured it out correctly. Here's my current code:
// Window.h
class Window
{
public:
// some getters/setters and other functions
private:
// members are here
};
// on another file
int func1(Window* win /*I want to remove this */, ...) {
// use win and other parameters
}
And here's the smart pointers approach.
// class Window as declared above
// file.h
namespace space
{
struct context;
context* make_context(std::shared_ptr<Window> const& win); // const& to avoid copy
void destroy_context(context* ctx);
int func1(...); // note that ... is used to show some params whose type isn't important for the question.
}
// some other functions
// file.cpp
namespace space
{
struct context
{
std::weak_ptr<Window> target;
};
context* make_context(std::shared_ptr<Window> const& win) // const& to avoid copy
{
context* ctx = new context{};
ctx->target = win;
return ctx;
}
void destroy_context(context* ctx)
{
if(ctx != nullptr)
{
delete ctx;
ctx = nullptr;
}
}
int func1(...)
{
// use ... params
} // int func1(...)
} // namespace space
// main.cpp
int main(int, char**)
{
std::shared_ptr<Window> window{new Window{/*some arguments*/}};
auto ctx{space::make_context(window)};
int func1();
// some other code
delete ctx;
}
As explained already in the various comments, a parameter which is a pointer like Window* will never create a copy of the Window object. This is why a pointer is made for.
Before trying to figure out more complex tools like smart pointers, I suggest you first spend time understanding C++ fundamental. You should start by what is a value, what is a pointer, what is a reference.
I'm trying to create a simple renderer for an SDL2 application, and thought I would try to wrap the SDL_* resources in unique_ptr with their SDL_Destroy* functions as deleters, as well as an interface for creating that renderer that could handle the cases where it fails gracefully with an std::variant or an std::optional, i.e.:
My SDL renderer is a simple class with a boolean and a unique_ptr to a window, as such:
using SDLWindowUptr = std::unique_ptr<SDL_Window, std::function<void(SDL_Window*)>>;
template <Value, Error>
using either = std::variant<Value, Error>;
enum class SDLRendererError {
SDLInitFailed, WindowCreationFailed
};
class SDLRenderer {
public:
static either<SDLRenderer, SDLRendererError> createRenderer();
private:
explicit SDLRenderer(SDLWindowUptr window):
_isRunning{false},
_window{std::move(window)}
{}
public: // Allow moves, forbid copies
SDLRenderer(const SDLRenderer& other) = delete;
SDLRenderer(SDLRenderer&& other) = default;
SDLRenderer& operator=(const SDLRenderer& other) = delete;
SDLRenderer& operator=(SDLRenderer&& other) = default;
public:
int run();
private:
bool _isRunning;
SDLWindowUptr _window;
};
I simply init this class in the factory method by initializing the SDL with SDL_INIT_VIDEO, then create an SDL_Window which I move into the renderer class if it has been created successfully:
either<SDLRenderer, SDLRendererError> SDLRenderer::createRenderer() {
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return SDLRendererError:SDLInitFailed;
}
auto windowUptr = SDLWindowUptr{
SDL_CreateWindow("Title",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
1280, 768,
SDL_WINDOW_RESIZABLE),
SDL_DestroyWindow
};
if (!windowUptr) {
return SDLRendererError::WindowCreationFailed;
}
return SDLRenderer{std::move(windowUptr)};
}
And in my main:
auto result = SDLRenderer::createRenderer();
if (std::holds_alternative<SDLRenderer>(result) {
auto& renderer = std::get<SDLRenderer>(result);
return renderer.run();
}
The SDL initialization completes successfully, as does the window creation.
Now this code actually yields an application where the window opens then closes instantly, and the main loop keeps running (it's only checking SDL_PollEvent and that's it), while SDL_GetError keeps spouting the same error message:
The event system has been shut down
Here's the code for the main loop:
int SDLRenderer::run()
{
auto event = SDL_Event{};
_isRunning = true;
// Main loop
while(_isRunning) {
while(SDL_PollEvent(&event)) {
onEvent(&event);
}
std::cout << "[Loop] SDL Error: " << SDL_GetError() << "\n";
SDL_Delay(200);
}
return 0;
}
Everything runs fine if I don't use a variant (or an optional with exactly the same usage) in the process, with exactly the same initialization code on the SDL side.
What am I missing about variants and optionals, or maybe about my code that actually causes an issue when used inside a variant/optional?
I'm trying to make an array of class filePlayerGui and when I try to initialise it in the constructor it won't let me do so
class MainComponent : public Component,
public MenuBarModel
{
public:
//==============================================================================
/** Constructor */
MainComponent (Audio& audio_);
/** Destructor */
~MainComponent();
void resized() override;
//MenuBarEnums/Callbacks========================================================
enum Menus
{
FileMenu=0,
NumMenus
};
enum FileMenuItems
{
AudioPrefs = 1,
NumFileItems
};
StringArray getMenuBarNames() override;
PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName) override;
void menuItemSelected (int menuItemID, int topLevelMenuIndex) override;
private:
Audio& audio;
FilePlayerGui filePlayerGui[2] {audio.getFilePlayer(0), audio.getFilePlayer(1)};
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
The filePlayerGui comes up with this error "Copying array element of type 'FilePlayerGui' invokes deleted constructor". I have tried initialising it in the .cpp file that I'll down below but then it tells me that I need an array initialiser
MainComponent::MainComponent (Audio& audio_) : audio (audio_)
{
setSize (500, 400);
addAndMakeVisible(filePlayerGui[0]);
addAndMakeVisible(filePlayerGui[1]);
}
MainComponent::~MainComponent()
{
}
void MainComponent::resized()
{
filePlayerGui[0].setBounds (0, 0, getWidth(), 40);
}
//MenuBarCallbacks==============================================================
StringArray MainComponent::getMenuBarNames()
{
const char* const names[] = { "File", 0 };
return StringArray (names);
}
PopupMenu MainComponent::getMenuForIndex (int topLevelMenuIndex, const String& menuName)
{
PopupMenu menu;
if (topLevelMenuIndex == 0)
menu.addItem(AudioPrefs, "Audio Prefrences", true, false);
return menu;
}
void MainComponent::menuItemSelected (int menuItemID, int topLevelMenuIndex)
{
if (topLevelMenuIndex == FileMenu)
{
if (menuItemID == AudioPrefs)
{
AudioDeviceSelectorComponent audioSettingsComp (audio.getAudioDeviceManager(),
0, 2, 2, 2, true, true, true, false);
audioSettingsComp.setSize (450, 350);
DialogWindow::showModalDialog ("Audio Settings",
&audioSettingsComp, this, Colours::lightgrey, true);
}
}
}
Copying array element of type FilePlayerGui invokes deleted constructor
Means that some variant this line is in the declaration of the FilePlayerGui:
FilePlayerGui(const FilePlayerGui&) = delete
Meaning that a FilePlayerGui cannot be copied: https://en.cppreference.com/w/cpp/language/copy_constructor#Deleted_implicitly-declared_copy_constructor
There are workarounds, but you are skirting the author of FilePlayerGui's intent for the class. So the correct answer should stop here. Any use of FilePlayerGui should be done through the the classes audio member, using either: audio.getFilePlayer(0) or audio.getFilePlayer(1). (If this is the only member of MainComponent in all likelihood MainComponent should be eliminated.)
If you want to know how to do bad things, which I would reject in any code review, you can either create filePointerGui as:
FilePointerGui* filePointerGui[2] which would be intialized as:
MainComponent::MainComponent(Audio& audio_) : audio(audio_), filePointerGui({ &audio.getFilePlayer(0), &audio.getFilePlayer(1) })
Access would be performed as:
*filePointerGui[0]
Live Example
reference_wrapper<FilePointerGui> filePointerGui[2] which would be initialized as:
MainComponent::MainComponent(Audio& audio_) : audio(audio_), filePointerGui({ audio.getFilePlayer(0), audio.getFilePlayer(1) })
Access would be performed as:
filePointerGui[0].get()
Live Example
It's probably worth stressing once more this is bad code because it tries to outsmart the language and work around the intent of the classes design. But this is c++ so you can do it.
EDIT: It looks like I'm completely misinformed. Please close this thread. Gah.
For the record, the following compiles and works:
class ForeverAlone
{
private:
int m_friends;
HANDLE m_handle;
public:
ForeverAlone()
{
m_handle = CreateThread(NULL, 0, &ForeverAlone::SadThread, reinterpret_cast<void*>(this), 0, NULL);
}
~ForeverAlone()
{
if (m_handle != NULL)
CloseHandle(m_handle);
}
protected:
static unsigned long WINAPI SadThread(void* param)
{
ForeverAlone* thisObject = reinterpret_cast<ForeverAlone*>(param);
// is there any way for me to access:
thisObject->m_friends;
}
};
Original question: I have a static protected thread method, which I pass an object to. Can I somehow make the class friend itself so I can access its private members?
All class methods, static or not, are automatically "friends" of the class. Friend is used to allow external functions and classes access to a class. The class is always its own "friend".
Do this:
extern "c" DWORD __stdcall CInterfaceSadThread(LPVOID lpThreadParameter);
class ForeverAlone
{
private:
int m_friends;
HANDLE m_handle;
public:
ForeverAlone()
{
m_handle = CreateThread(NULL, 0,
&CInterfaceSadThread,
//
// You may get arguments about using static_cast here
// I still prefer reinterpret_cast as it makes it stick out
// Thus I check it more carefully when I see it.
// For this situation it works correctly
// As casting to void* and back to the original are guaranteed.
reinterpret_cast<void*>(this),
0, NULL);
}
~ForeverAlone()
{
if (m_handle != NULL)
CloseHandle(m_handle)
}
protected:
friend DWORD CInterfaceSadThread(LPVOID lpThreadParameter);
DWORD WINAPI SadThread()
{
// Do Stuff here
// Note: Just because you get here does not mean that the object is finished
// initializing. The parent thread may have been suspended after this
// one was created. Thus checking the state of member variables at this
// point is dangerous unless you can guarantee that construction has finished
return result;
}
};
Then in the callback just access your function;
extern "c" DWORD __stdcall CInterfaceSadThread(LPVOID lpThreadParameter)
{
// Note: You can only cast back to ForeverAlone* so be carefull
// Hence I use reinterpret_cast as this forces me to double check.
ForeverAlone* alone = reinterpret_cast<ForeverAlone*>(lpThreadParameter);
return alone->SadThread();
}
I'm writing a GLFW app, in which I've wrapped the function calls into a simple class. I'm having trouble setting the key callback.
My class is defined as:
class GAME
{
private:
bool running;
public:
GAME();
int execute();
void events(int, int);
int loop();
int render();
};
The execute function is:
int GAME::execute()
{
glfwOpenWindow(640, 320, 8, 8, 8, 8, 0, 0, GLFW_WINDOW);
glfwSetWindowTitle("Viraj");
glfwSetKeyCallback(events);
running = true;
while(glfwGetWindowParam(GLFW_OPENED))
{
glfwPollEvents();
loop();
render();
}
return 0;
}
Compiling the following code on Visual Studio 2010 gives the error:
error C3867: 'GAME::events': function call missing argument list; use '&GAME::events' to create a pointer to member
Using &GAME::events gives:
error C2664: 'glfwSetKeyCallback' : cannot convert parameter 1 from 'void (__thiscall GAME::* )(int,int)' to 'GLFWkeyfun' 1> There is no context in which this conversion is possible
The code examples provided in the other answers don't describe how to redirect your callback to a per-object member function, with possibly any number of objects. Making your class a singleton will constrain your design and will not scale to multiple glfw windows.
The scalable solution is to set the glfw window user pointer to your object and then fetch it in the callback, and call the member function :
class MyGlWindow
{
public:
void mouseButtonPressed();
};
void makeWindow()
{
GLFWwindow* glfwWindow;
MyGlWindow* myWindow;
/* ... Initialize everything here ... */
glfwSetWindowUserPointer(glfwWindow, myWindow);
auto func = [](GLFWwindow* w, int, int, int)
{
static_cast<MyGlWindow*>(glfwGetWindowUserPointer(w))->mouseButtonPressed( /* ... */ );
}
glfwSetMouseButtonCallback(glfwWindow, func);
}
This solution is shorter and will work for any number of windows.
I also ran into this problem with another glfw callback function, but I didn't want to declare my class method as static, because I needed to access the member variables within. So I tried std::function and std::bind for giving me the ability to bind an instance method as the callback function, but unfortunately it's not an option when working with C callbacks.
The answer to this problem is also stated in the GLFW FAQ "How do I use C++ methods as callbacks":
You cannot use regular methods as callbacks, as GLFW is a C library
and doesn’t know about objects and this pointers. If you wish to
receive callbacks to a C++ object, use static methods or regular functions as callbacks, store the pointer to the object you wish to
call in some location reachable from the callbacks and use it to call
methods on your object.
However, this encouraged me to apply the Singleton pattern for my callback class and integrate it as following:
the callback method of my class is still static, so it can be specified/used as glfw callback
this static callback method makes use of the singleton and passes the callback parameters to an instance method
this instance method actually handles the callback parameters, with the benefit of being able to access the member variables
This is what it looks like:
// Input.h (the actual callback class for glfwSetMouseButtonCallback)
class Input
{
public:
static Input& getInstance() // Singleton is accessed via getInstance()
{
static Input instance; // lazy singleton, instantiated on first use
return instance;
}
static void mouseButtonCallback(int key, int action) // this method is specified as glfw callback
{
//here we access the instance via the singleton pattern and forward the callback to the instance method
getInstance().mouseButtonCallbackImpl(key, action);
}
void mouseButtonCallbackImpl(int key, int action) //this is the actual implementation of the callback method
{
//the callback is handled in this instance method
//... [CODE here]
}
private:
Input(void) // private constructor necessary to allow only 1 instance
{
}
Input(Input const&); // prevent copies
void operator=(Input const&); // prevent assignments
};
and in my main.cpp:
Input &hexmap = Input::getInstance(); // initialize the singleton
//The glfw callback is set up as follows:
glfwSetMouseButtonCallback( &Input::mouseButtonCallback); // specifying the static callback method, which internally forwards it to the instance method
There is a C++ syntax for pointing to class member methods but you cannot pass them to a C style API. C understands function calls and every non-static object method, taking your events as an example, looks like this thinking in C terms: void events(void* this, int, int); meaning that every method apart from the standard arguments also gets a this pointer silently passed.
To make your events C compatible make it static void events(int, int);. This way it will follow the C calling semantics - it will not require a this pointer getting passed. You have to also somehow pass your object to this callback in some other manner (if you need this object's data in the callback).
I had the same problem and after reading this thread I came up with a similar solution. I think it is a bit cleaner this way. It's based on static function but it is nested inside the class where we set all things.
Header looks like this:
class Application
{
public:
...
private:
...
void MousePositionCallback(GLFWwindow* window, double positionX, double positionY);
void KeyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
...
class GLFWCallbackWrapper
{
public:
GLFWCallbackWrapper() = delete;
GLFWCallbackWrapper(const GLFWCallbackWrapper&) = delete;
GLFWCallbackWrapper(GLFWCallbackWrapper&&) = delete;
~GLFWCallbackWrapper() = delete;
static void MousePositionCallback(GLFWwindow* window, double positionX, double positionY);
static void KeyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
static void SetApplication(Application *application);
private:
static Application* s_application;
};
};
And the source code:
void Application::GLFWCallbackWrapper::MousePositionCallback(GLFWwindow* window, double positionX, double positionY)
{
s_application->MousePositionCallback(window, positionX, positionY);
}
void Application::GLFWCallbackWrapper::KeyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
s_application->KeyboardCallback(window, key, scancode, action, mods);
}
void Application::GLFWCallbackWrapper::SetApplication(Application* application)
{
GLFWCallbackWrapper::s_application = application;
}
Application* Application::GLFWCallbackWrapper::s_application = nullptr;
void Application::MousePositionCallback(GLFWwindow* window, double positionX, double positionY)
{
...
}
void Application::KeyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
...
}
void Application::SetCallbackFunctions()
{
GLFWCallbackWrapper::SetApplication(this);
glfwSetCursorPosCallback(m_window, GLFWCallbackWrapper::MousePositionCallback);
glfwSetKeyCallback(m_window, GLFWCallbackWrapper::KeyboardCallback);
}
Inspired by N0vember's answer, I present you even more generic and dynamic solution:
class MyGlWindow {
public:
std::function<void(MyGlWindow*)> onClose;
std::function<void(MyGlWindow*, int, int, int)> onMouseClick = [](auto self, int, int, int) { /*some default behavior*/ };
};
void makeWindow() {
GLFWwindow* glfwWindow;
MyGlWindow* myWindow;
/* ... Initialize everything here ... */
glfwSetWindowUserPointer(glfwWindow, myWindow);
#define genericCallback(functionName)\
[](GLFWwindow* window, auto... args) {\
auto pointer = static_cast<MyGlWindow*>(glfwGetWindowUserPointer(window));\
if (pointer->functionName) pointer->functionName(pointer, args...);\
}
glfwSetWindowCloseCallback(glfwWindow, genericCallback(onClose));
glfwSetMouseButtonCallback(glfwWindow, genericCallback(onMouseClick));
myWindow->onMouseClick = [](auto self, int, int, int) {
std::cout << "I'm such a rebel" << std::endl;
self->onClose = [](auto self) {
std::cout << "I'm such a rebellion" << std::endl;
};
};
}
In the header file make the events(int, int) to a static method. That solved the issue for me.
class GAME
{
private:
bool running;
public:
GAME();
int execute();
static void events(int, int); //Changed here to static void
int loop();
int render();
};
This is a useful discussion of possible solutions that helped me with the same problem, and I'm adding my solution in case it proves useful.
Problem Statement
My scenario is more general than the ones addressed by BIC, L.Senionis, and N0vember. In particular, my use case requires:
Generally, instance's data must be accessible to the callback
Many applications can be created using a common set of response handlers
In an application, any number of windows may be created
The set of callbacks attached to each window should be mixed and matched from a certain library of possible responders.
Proposed Solution Usage
The simple singleton design no longer solves the problem. Instead, I provide a GLFWResponder superclass that handles all of the setup complexity. In order to use the class and attach response to a window, here is what is required.
// Implement custom responder
class MyResponder : public GLFWResponder {
public:
virtual void cursor_position_callback(GLFWwindow* w, double x, double y) {...}
... override relevant callbacks ...
};
// in main ************************************************
// Assuming initialized GLFWwindow* my_window and my_other_window
MyResponder resp;
MyResponder resp2; // Can be another subclass of GLFWResponder
// Two responders can respond to same window
resp.respond_to(my_window, GLFWResponder::CURSOR_POSITION);
resp2.respond_to(my_window, GLFWResponder::CURSOR_POSITION);
// One responder can respond to multiple windows
resp2.respond_to(my_other_window, GLFWResponder::CURSOR_POSITION);
// One window can have different handlers for different events
resp.respond_to(my_other_window, GLFWResponder::CURSOR_ENTER);
Proposed Solution Implementation
Here is the sketch of the GLFWResponder implementation, fully functional, but with some TODO's. There may be some implications on performance, which I have not yet investigated.
// GLFWResponder.h ************************************************
/**
* Responder superclass that allows subclasses to handle events from multiple
* GLFW windows (which have only C API for callbacks).
* Callbacks are automatically cleaned up when responder goes out of scope.
*/
class GLFWResponder {
public:
virtual ~GLFWResponder();
// Interface -----------------------------------
enum GLFWEventType {
CURSOR_POSITION = 0,
CURSOR_ENTER = 1
// TODO: add support for other callbacks
};
void respond_to(GLFWwindow* window, GLFWEventType event);
bool does_respond_to(GLFWwindow* window, GLFWEventType event) const;
// Subclasses implement ------------------------
virtual void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
virtual void cursor_enter_callback(GLFWwindow* window, int entered);
// TODO: add support for other callbacks
// Under the hood ------------------------------
static std::set<GLFWResponder*> getResponders(GLFWwindow* windo, GLFWEventType event);
private:
// Windows and events that this instance responds to
std::set<std::pair<GLFWwindow*, GLFWEventType> > enabled_events_;
// Global responders keyed by events they respond to
// (each responder knows which windows it responds to)
static std::map<GLFWEventType, std::set<GLFWResponder*> > responders_;
};
// GLFWResponder.cpp **************************************************
namespace {
void cursor_position_callback_private(GLFWwindow* window, double xpos, double ypos) {
for (GLFWResponder* r : GLFWResponder::getResponders(window, GLFWResponder::CURSOR_POSITION)) {
r->cursor_position_callback(window, xpos, ypos);
}
}
void cursor_enter_callback_private(GLFWwindow* window, int entered) {
for (GLFWResponder* r : GLFWResponder::getResponders(window, GLFWResponder::CURSOR_ENTER)) {
r->cursor_enter_callback(window, entered);
}
}
} // namespace
std::map<GLFWResponder::GLFWEventType, std::set<GLFWResponder*> > GLFWResponder::responders_;
GLFWResponder::~GLFWResponder() {
for (auto& pr : responders_) {
pr.second.erase(this);
}
// TODO: also clean up window's callbacks
}
void GLFWResponder::respond_to(GLFWwindow* window, GLFWResponder::GLFWEventType event) {
enabled_events_.insert(std::make_pair(window, event));
responders_[event].insert(this);
if (event == CURSOR_POSITION) {
glfwSetCursorPosCallback(window, cursor_position_callback_private);
} else if (event == CURSOR_ENTER) {
glfwSetCursorEnterCallback(window, cursor_enter_callback_private);
} else {
// TODO: add support for other callbacks
LOG(FATAL) << "Unknown GLFWResponder event: " << event;
}
}
bool GLFWResponder::does_respond_to(GLFWwindow* window, GLFWEventType event) const {
return enabled_events_.find(std::make_pair(window, event)) != enabled_events_.end();
}
std::set<GLFWResponder*> GLFWResponder::getResponders(
GLFWwindow* window, GLFWEventType event) {
std::set<GLFWResponder*> result;
auto it = responders_.find(event);
if (it != responders_.end()) {
for (GLFWResponder* resp : it->second) {
if (resp->does_respond_to(window, event)) {
result.insert(resp);
}
}
}
return result;
}
void GLFWResponder::cursor_position_callback(
GLFWwindow* window, double xpos, double ypos) {
// TODO: fail with message "GLFWResponder::do_respond called on a subclass that does not implement a handler for that event"
}
void GLFWResponder::cursor_enter_callback(GLFWwindow* window, int entered) {
// TODO: fail with message "GLFWResponder::do_respond called on a subclass that does not implement a handler for that event"
}