I have an error when I am trying to use std::make_unique. I probably have made a very simple mistake and I would be thankful if someone pointed it out. I am using GLAD and GLFW as 3rd party libraries. I get an error code of C2661 when I run it, C2661 'Window::Window': no overloaded function takes 3 arguments on the next code snippet in window.cpp.
return std::make_unique<Window>(std::move(nativeWindow), width, height);
Window.hpp
#pragma once
#include <memory>
#include <string>
#include <GLFW/glfw3.h>
struct Window final {
public:
std::unique_ptr<Window> createWindow(int width, int height, std::string title);
bool shouldClose() { return glfwWindowShouldClose(nativeWindow); }
void swapBuffers() { glfwSwapBuffers(nativeWindow); }
private:
GLFWwindow* nativeWindow;
int width;
int height;
std::string title;
};
Window.cpp
#include "Window.hpp"
std::unique_ptr<Window> Window::createWindow(int width, int height, std::string title) {
nativeWindow = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
glfwMakeContextCurrent(nativeWindow);
return std::make_unique<Window>(std::move(nativeWindow), width, height);
}
sorry for bad code quality.
Your Window
class does not have a constructor taking GLFWwindow*, int, int
as would be required for this:
return std::make_unique<Window>(std::move(nativeWindow), width, height);
However, it seems you are encapsulating the wrong thing.
Window
instance is copied or moved, there will suddenly be two owners of the GLFWwindow
, with a double free
later likely.Window
is destroyed, you don't call glfwDestroyWindow
to free the resource, which will leak.Read The rule of 3/5/0.
What you should be doing is really to store a unique_ptr<GLFWwindow>
in Window
to make the problems mentioned above go away without having to implement the manual resource management mentioned in The rule of 3/5/0.
Example:
struct Window final {
public:
Window(int width, int height, std::string title);
inline bool shouldClose() { return glfwWindowShouldClose(nativeWindow.get()); }
inline void swapBuffers() { glfwSwapBuffers(nativeWindow.get()); }
private:
struct glfwWindowDestroyer {
void operator()(GLFWwindow* win) const {
glfwDestroyWindow(win);
}
};
std::unique_ptr<GLFWwindow, glfwWindowDestroyer> nativeWindow;
int width;
int height;
std::string title;
};
The constructor implementation would then be:
Window::Window(int width, int height, std::string title) :
nativeWindow(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr)),
width(width),
height(height),
title(std::move(title))
{
glfwMakeContextCurrent(nativeWindow.get());
}
That way the createWindow
function (which should have been static
) can be removed. Just create Window
s like normal C++ objects. Window
objects are now safely moveable (and non-copyable) without any extra tinkering.
If you for some reason still would like to have a helper function to create unique_ptr<Window>
s, you can, but as you will see, it will be rather pointless:
std::unique_ptr<Window>
Window::createWindow(int width, int height, std::string title) {
return std::make_unique<Window>(width, height, title);
}
There's not much of a gain to call Window::createWindow
instead of just calling std::make_unique<Window>
directly. Also, the use of unique_ptr<Window>
s is dubious. Window
is final
and it's not inheriting from anything. You should probably just store Window
s directly in a container.