Repository: Cvelth/vkfw
Pull request #14: Fix issues with `vkfw::UniqueHandle`
Author: login: marovira
Created: 2025-04-24T19:17:58Z | Merged: 2025-04-26T08:07:10Z

This fixes #12 and #13.

Note: I'm not overly sure of the wording in the README, so I'm open to suggestions.

Linked issue #12: Compiler error when defining `VULKAN_HPP_NO_SMART_HANDLE`
By default, `vkfw` will include `vulkan.hpp` unless disabled with `VKFW_NO_INCLUDE_VULKAN`. However, if `VULKAN_HPP_NO_SMART_HANDLE` is defined without `VKFW_NO_INCLUDE_VULKAN`, a compiler error is introduced as `vkfw` attempts to define its `UniqueHandle` as an alias of `vk::UniqueHandle` which doesn't exist.
Linked issue comments: user: login: Cvelth
created_at: 2025-04-23T13:50:20Z
body: Could you, please, fix this?

Either as a separate commit in the active PR or as a separate PR?

I think the right course of action in that situation is to add something like
```cpp
// (untested)
#if defined(VULKAN_HPP_NO_SMART_HANDLE) and not defined(VKFW_NO_SMART_HANDLE)
  #warning "`VKFW_NO_SMART_HANDLE` is overruled because it cannot function in `VULKAN_HPP_NO_SMART_HANDLE` mode"
  #define VKFW_NO_SMART_HANDLE
#endif
```
somewhere near the top of the header.

What do you think?
author_association: OWNER
user: login: marovira
created_at: 2025-04-23T13:55:03Z
body: A separate PR would be best I think, and yeah I'll fix it. Just wanted to log the issue so I don't forget.
author_association: CONTRIBUTOR
user: login: marovira
created_at: 2025-04-23T20:59:03Z
body: Question: what happens if the users have a setup like this:
* Define `VKFW_NO_INCLUDE_VULKAN`
* Define `VULKAN_HPP_NO_SMART_HANDLES`

With this setup, `vkfw` will use its own implementation for the `UniqueHandle`. Should `VULKAN_HPP_NO_SMART_HANDLES` still define `VKFW_NO_SMART_HANDLE` or should it be left as is?
I think it shoud be left as is, so the actual guard would look something like this:
```c++
#if defined(VULKAN_HPP_NO_SMART_HANDLE) && !defined(VKFW_NO_SMART_HANDLE) && !defined(VKFW_NO_INCLUDE_VULKAN)
#define VKFW_NO_SMART_HANDLE
#endif
```
author_association: CONTRIBUTOR
user: login: Cvelth
created_at: 2025-04-24T17:00:47Z
body: (sorry for the slow reply, was kind of busy last couple of days)

Good catch! Let's go with your check!

But please add a warning about what's going on (we're technically overriding a piece of user's configuration) both if it happens and somewhere in the readme!
author_association: OWNER

Diff:
diff --git a/README.md b/README.md
index e9d3123..5030d3e 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,10 @@ For each function which constructs a GLFW handle of type `vkfw::Type` VKFW provi
 
 As all the deleters are known at compiler time and don't need to store anything extra - the only downside is a slight compilation time increase.
 
+ > [!WARNING]
+ > The destructors for `vkfw::UniqueInstance`, `vkfw::UniqueWindow`, and `vkfw::UniqueCursor` will will swallow any exceptions or error codes (if using `VKFW_NO_EXCEPTIONS`) that are produced in the destruction of the underlying handle.
+ > If you wish to be notified of these kinds of errors, you are encouraged to use `vkfw::setErrorCallback` to bind a function that captures errors.
+
 ### Callbacks
 To allow using lambdas as callbacks, `GLFWwindow` user pointer is used internally to store `std::function` objects instead of c-style function pointers.
 These objects are accessible through `vkfw::Window::callbacks()` (or `accessWindowCallbacks(GLFWwindow *)` if enhanced mode is disabled) function and can be set directly, for example:
@@ -135,6 +139,10 @@ When a `vkfw` function returns an error value code, an exception is thrown unles
 ### `VKFW_NO_SMART_HANDLE`
 The `UniqueHandle` helper class and all the unique handle types and functions returning them are not compiled if this precompiler definition is defined.
 
+> [!WARNING]
+> If `VKFW_NO_INCLUDE_VULKAN_HPP` isn't defined, then `vkfw` will use the smart handles from Vulkan-HPP directly. In the event that `VULKAN_HPP_NO_SMART_HANDLES` is defined, then `VKFW_NO_SMART_HANDLE` will also be defined if it hasn't been defined already and a compiler warning will be issued.
+> You can avoid this behavior by defining either `VKFW_NO_SMART_HANDLE` or `VKFW_NO_INCLUDE_VULKAN_HPP` before including `<vkfw/vkfw.hpp>`
+
 ### `VKFW_NO_STD_FUNCTION_CALLBACKS`
 Disables c++ callbacks based on `std::function`. Define this if you cannot afford an extra function call per event for extra usability. Note, that original callbacks do not use `enum class`es and it's your responcibility to cast the values correctly inside the callback itself. Or you can just use original preprocessor definitions.
 
@@ -148,6 +156,9 @@ VKFW includes `vulkan.h` by default (same as GLFW with `GLFW_INCLUDE_VULKAN` def
 VKFW includes `vulkan.hpp` by default. This preprocessor definition allows to disable the inclusion.
 When it is not defined, some of the vulkan.hpp helpers are used (like `UniqueHandle`), otherwise an alternatives are declared.
 
+> [!NOTE]
+> This flag can cause an override of `VKFW_NO_SMART_HANDLE`. See the documentation for `VKFW_NO_SMART_HANDLE` for more details.
+
 ### `VKFW_NO_LEADING_e_IN_ENUMS`
 Removes leading `e` from enum values, for example `vkfw::Key::eA` becomes `vkfw::Key::A` and `vkfw::Key::e1` becomes `vkfw::Key::_1`.
 
diff --git a/include/vkfw/vkfw.hpp b/include/vkfw/vkfw.hpp
index 6a49b7a..2d9c3eb 100644
--- a/include/vkfw/vkfw.hpp
+++ b/include/vkfw/vkfw.hpp
@@ -83,6 +83,15 @@
   #include <vulkan/vulkan.hpp>
 #endif
 
+#if defined(VULKAN_HPP_NO_SMART_HANDLE) && !defined(VKFW_NO_SMART_HANDLE)                          \
+  && !defined(VKFW_NO_INCLUDE_VULKAN_HPP)
+  #pragma message(                                                                                 \
+    "warning: VKFW_NO_SMART_HANDLE will be defined as vkfw requires Vulkan-HPP handles when "      \
+    "VKFW_NO_INCLUDE_VULKAN_HPP isn't defined. You can silence this warning by defining "          \
+    "VKFW_NO_SMART_HANDLE or VKFW_NO_INCLUDE_VULKAN_HPP before including <vkfw/vkfw.hpp>")
+  #define VKFW_NO_SMART_HANDLE
+#endif
+
 #ifdef VKFW_DISABLE_ENHANCED_MODE
   #ifndef VKFW_NO_SMART_HANDLE
     #define VKFW_NO_SMART_HANDLE
@@ -3124,7 +3133,18 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    // Warning: this function will swallow any exceptions or return codes (if using
+    // VKFW_NO_EXCEPTIONS). If you wish to be notified of any errors, please use
+    // vkfw::setErrorCallback to bind a function that captures errors.
+  #ifndef VKFW_NO_EXCEPTIONS
+    try {
+  #endif
+      static_cast<void>(instance.destroy());
+  #ifndef VKFW_NO_EXCEPTIONS
+    } catch (...) {}
+  #endif
+  }
 };
   #ifndef VKFW_NO_INCLUDE_VULKAN_HPP
 template <>
@@ -3138,7 +3158,18 @@ template <> class VKFW_NAMESPACE::UniqueHandleTraits<VKFW_NAMESPACE::Instance> {
 };
 
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Window> {
-  VKFW_INLINE void destroy(Window &window) { static_cast<void>(window.destroy()); }
+  VKFW_INLINE void destroy(Window &window) {
+    // Warning: this function will swallow any exceptions or return codes (if using
+    // VKFW_NO_EXCEPTIONS). If you wish to be notified of any errors, please use
+    // vkfw::setErrorCallback to bind a function that captures errors.
+  #ifndef VKFW_NO_EXCEPTIONS
+    try {
+  #endif
+      static_cast<void>(window.destroy());
+  #ifndef VKFW_NO_EXCEPTIONS
+    } catch (...) {}
+  #endif
+  }
 };
   #ifndef VKFW_NO_INCLUDE_VULKAN_HPP
 template <>
@@ -3152,7 +3183,18 @@ template <> class VKFW_NAMESPACE::UniqueHandleTraits<VKFW_NAMESPACE::Window> {
 };
 
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Cursor> {
-  VKFW_INLINE void destroy(Cursor &cursor) { static_cast<void>(cursor.destroy()); }
+  VKFW_INLINE void destroy(Cursor &cursor) {
+    // Warning: this function will swallow any exceptions or return codes (if using
+    // VKFW_NO_EXCEPTIONS). If you wish to be notified of any errors, please use
+    // vkfw::setErrorCallback to bind a function that captures errors.
+  #ifndef VKFW_NO_EXCEPTIONS
+    try {
+  #endif
+      static_cast<void>(cursor.destroy());
+  #ifndef VKFW_NO_EXCEPTIONS
+    } catch (...) {}
+  #endif
+  }
 };
   #ifndef VKFW_NO_INCLUDE_VULKAN_HPP
 template <>
@@ -3195,10 +3237,14 @@ namespace VKFW_NAMESPACE {
   }
   VKFW_NODISCARD_WHEN_NO_EXCEPTIONS VKFW_INLINE typename ResultValueType<void>::type
   Cursor::destroy() {
-    glfwDestroyCursor(m_cursor);
-    m_cursor = nullptr;
-    return createResultValue(Result::VKFW_ENUMERATOR(Success),
-                             VKFW_NAMESPACE_STRING "::Cursor::destroy");
+    if (m_cursor) {
+      glfwDestroyCursor(m_cursor);
+      m_cursor = nullptr;
+      return createResultValue(getError(), VKFW_NAMESPACE_STRING "::Cursor::destroy");
+    } else {
+      return createResultValue(Result::VKFW_ENUMERATOR(Success),
+                               VKFW_NAMESPACE_STRING "::Cursor::destroy");
+    }
   }
 #endif
 


Reviews:
user: login: Cvelth
body: Looks really good! Thanks for taking care of this!
state: APPROVED
author_association: OWNER
submitted_at: 2025-04-25T05:45:55Z
user: login: marovira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T13:22:14Z
user: login: marovira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T13:48:33Z
user: login: Cvelth
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-25T14:15:42Z
user: login: Cvelth
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-25T14:17:03Z
user: login: marovira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T16:22:54Z
user: login: Cvelth
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-25T16:52:42Z
user: login: marovira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T17:01:10Z
user: login: Cvelth
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-25T17:04:18Z

Review comments:
diff_hunk: @@ -135,6 +135,12 @@ When a `vkfw` function returns an error value code, an exception is thrown unles
 ### `VKFW_NO_SMART_HANDLE`
 The `UniqueHandle` helper class and all the unique handle types and functions returning them are not compiled if this precompiler definition is defined.
 
+> [!WARNING]
+> If `VKFW_NO_INCLUDE_VULKAN_HPP` isn't defined, then `vkfw` will use the smart handles from Vulkan-HPP directly. In the event that `VULKAN_HPP_NO_SMART_HANDLES` is defined, then `VKFW_NO_SMART_HANDLE` will also be defined if it hasn't been defined already and a compiler warning will be issued.
+> You can silence this warning by either:
+> * Defining `VKFW_NO_SMART_HANDLE` before including `<vkfw/vkfw.hpp>` or,
+> * Defining `VKFW_NO_INCLUDE_VULKAN_HPP` before including `<vkfw/vkfw.hpp>`.
path: README.md
user: login: Cvelth
body: I'd probably go with
```
You can avoid this behavior by defining either `VKFW_NO_SMART_HANDLE` or `VKFW_NO_INCLUDE_VULKAN_HPP` before including `<vkfw/vkfw.hpp>`.
```
created_at: 2025-04-25T05:33:29Z
author_association: OWNER
diff_hunk: @@ -148,6 +154,9 @@ VKFW includes `vulkan.h` by default (same as GLFW with `GLFW_INCLUDE_VULKAN` def
 VKFW includes `vulkan.hpp` by default. This preprocessor definition allows to disable the inclusion.
 When it is not defined, some of the vulkan.hpp helpers are used (like `UniqueHandle`), otherwise an alternatives are declared.
 
+> [!NOTE]
+> This flag can cause an override of `VKFW_NO_SMART_HANDLE`. See the documentation for `VKFW_NO_SMART_HANDLE` for more details.
path: README.md
user: login: Cvelth
body: Very enterprise!
created_at: 2025-04-25T05:33:49Z
author_association: OWNER
diff_hunk: @@ -83,6 +83,21 @@
   #include <vulkan/vulkan.hpp>
 #endif
 
+#if defined(VULKAN_HPP_NO_SMART_HANDLE) && !defined(VKFW_NO_SMART_HANDLE)                          \
+  && !defined(VKFW_NO_INCLUDE_VULKAN_HPP)
+  #if defined(_MSC_VER)
+    #pragma message(                                                                               \
+      "warning: VKFW_NO_SMART_HANDLE will be defined as vkfw requires Vulkan-HPP handles when "    \
+      "VKFW_NO_INCLUDE_VULKAN_HPP isn't defined. You can silence this warning by defining "        \
+      "VKFW_NO_SMART_HANDLE or VKFW_NO_INCLUDE_VULKAN_HPP")
+  #else
+    #warning "VKFW_NO_SMART_HANDLE will be defined as vkfw requires Vulkan-HPP handles when \
+VKFW_NO_INCLUDE_VULKAN_HPP isn't defined. You can silence this warning by defining \
+VKFW_NO_SMART_HANDLE or VKFW_NO_INCLUDE_VULKAN_HPP"
+  #endif
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: Ah, right, I totally forgot about this. Good catch!

But looking into it, both `gcc` and `clang` seem to support `#pragma message` so let's just get rid of `#warning` to avoid having to spell the error twice.
created_at: 2025-04-25T05:42:03Z
author_association: OWNER
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: I'd wrap `try` and `catch` into an `#ifndef VKFW_HPP_NO_EXCEPTIONS`.

Also, I'd add another warning (`pragma message`) inside the catch block, so a warning about discarding errors is printed for anyone who would compile destructors with exception support.
created_at: 2025-04-25T05:45:23Z
author_association: OWNER
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: marovira
body: So the function should look like this?
```c++
#ifdef VKFW_HPP_NO_EXCEPTIONS
static_cast<void>(instance.destroy());
#else
try {
   static_cast<void>(instance.destry());
} catch (...) {}
#endif
```

As for the warning/message: having that message there will add noise to the compiler output that isn't really necessary as the behaviour is already documented in the `README`. It is also worth noting that this message will appear by default since `vkfw` builds with handles and exceptions if the user doesn't specify otherwise.
In addition, the message would have to be enabled independently of whether exceptions are enabled because the current behaviour already swallows error return codes in the event exceptions are disabled.
If you really believe that another warning is necessary, then there also needs to be a flag to silence it. That would mean the destroy functions would look something like this:
```c++
  VKFW_INLINE void destroy(Instance &instance) {
#ifndef VKFW_NO_HANDLE_DESTRUCTOR_WARNING
#pragma message("warning: unique handle destructors will swallow any exceptions or return codes. You can silence this warning by defining VKFW_NO_HANDLE_DESTRUCTOR_WARNING")
#endif
#ifdef VKFW_HPP_NO_EXCEPTIONS
   static_cast<void>(instance.destroy());
#else
    try {
      static_cast<void>(instance.destroy());
    } catch (...) {}
#endif
```

Thoughts?
created_at: 2025-04-25T13:22:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: marovira
body: To follow up: having the compiler issue a warning message is a bad idea in this case because *all* users would get it unless they explicitly disabled the handles. So if a user forgets to disable the handles (or doesn't want to for whatever reason) they now get that warning message on their builds whether they actually use the handles or not. 
Even having the flag to disable it would be annoying, because they'd have to silence a warning for something that they may not even use.
created_at: 2025-04-25T13:48:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: Yes, I realize that this will produce a warning by default. But don't forget that we're _discarding errors_ by default. Which is what worries me the most.

But I also don't want to disable automatic handles by default either - because they are like _the_ feature of these bindings.

In my mind, the way to go is something like
```cpp
// (untested)
UniqueHandle::~UniqueHandle() VKFW_NOEXCEPT {
#ifndef VKFW_HPP_NO_EXCEPTIONS
  try {
#endif

    if (m_value)
      this->destroy(m_value);

#ifndef VKFW_HPP_NO_EXCEPTIONS
  } catch(...) {
    // DANGER!!! Discarded Errors!

    #ifndef VKFW_ALLOW_DESTRUCTORS_TO_DISCARD_EXCEPTIONS
      #pragma message("warning: unique handle destructors will NEVER throw. "
                      "Which means exceptions passing through them WILL BE lost. "
                      "You can either disable exception altogether (by defining "
                      "`VKFW_HPP_NO_EXCEPTIONS`) or silence this warning (by defining "
                      "`VKFW_ALLOW_DESTRUCTORS_TO_DISCARD_EXCEPTIONS`)."
                      "If you use the second approach it's highly recommended you handle such "
                      "errors in another way, for example using `vkfw::setErrorCallback`");"
    #endif
  }
#endif
}
```

and then each user (who cares about warnings) to decide which way is better for them.

Of course it would also mean fully disabling the usage of `vk::UniqueHandle` in favor of `vkfw::UniqueHandle`, which is sad, but not a deal-breaker I'd say.

--------------------------------------------

But honestly, as I'm typing this out, I'm realizing that this might be an overkill. Considering even `vulkan_hpp` doesn't seem to do anything special to handle this corner case, and that's a huge and well maintained library 🤔.
created_at: 2025-04-25T14:15:42Z
author_association: OWNER
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: BTW, it looks like there's a bit of a misunderstanding. All the different flavors of `destroy` we have can stay the way they are. It's not like they are prevented from throwing! It's specifically destructors (as in, just `~UniqueHandle`) that is the problem.
created_at: 2025-04-25T14:17:03Z
author_association: OWNER
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: marovira
body: I honestly believe that the warning is completely overkill and too heavy handed for something like this. I can change the note on the `README` to a warning so it's more emphatic, but having it as a compiler warning that will appear whether you use the handles or not is excessive.

> BTW, it looks like there's a bit of a misunderstanding. All the different flavors of destroy we have can stay the way they are. It's not like they are prevented from throwing! It's specifically destructors (as in, just ~UniqueHandle) that is the problem.

I'm not changing all of them! The snippet I pasted might've been a bit misleading though. The only `destroy` functions I'm changing are the ones that belong to the `vkfw::CustomDestroy` structs. That way, it maintains compatibility with both `vkfw::UniqueHandle` and `vk::UniqueHandle` and only those two are affected by this change. Even then, I'm specifically *only* changing the ones for `vkfw::Instance` and `vkfw::Window`, since `vkfw::Cursor` can't throw anyway.

All remaining uses of `destroy` for those two handles will retain their normal behaviour.

Edit: as I'm re-reading this, I should probably change the wording of the `README` to reflect the fact that only `vkfw::UniqueInstance` and `vkfw::UniqueWindow` do this.
created_at: 2025-04-25T16:22:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: > I honestly believe that the warning is completely overkill and too heavy handed for something like this

Honestly, sure, let's turn the compilation-time warning into a comment instead. If someone runs into trouble with it, they'll probably be able to find it anyway.

> the ones that belong to the `vkfw::CustomDestroy` structs

Ah, ok, then misunderstanding is all mine! Sorry for the noise (it's been a while since I touched this code :D)

> since `vkfw::Cursor` can't throw anyway.

Wait, it can raise errors, specifically [`GLFW_NOT_INITIALIZED` and `GLFW_PLATFORM_ERROR`](https://www.glfw.org/docs/latest/group__input.html#ga81b952cd1764274d0db7fb3c5a79ba6a:~:text=Errors-,Possible%20errors%20include%20GLFW_NOT_INITIALIZED%20and%20GLFW_PLATFORM_ERROR.,-Reentrancy), meaning it _can_ throw!

Practically, think destroying the instance before destroying the cursor object.

> I should probably change the wording of the README to reflect the fact that only `vkfw::UniqueInstance` and `vkfw::UniqueWindow` do this.

Yes, please!
created_at: 2025-04-25T16:52:42Z
author_association: OWNER
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: marovira
body: > Wait, it can raise errors, specifically [GLFW_NOT_INITIALIZED and GLFW_PLATFORM_ERROR](https://www.glfw.org/docs/latest/group__input.html#ga81b952cd1764274d0db7fb3c5a79ba6a:~:text=Errors-,Possible%20errors%20include%20GLFW_NOT_INITIALIZED%20and%20GLFW_PLATFORM_ERROR.,-Reentrancy), meaning it can throw!
> Practically, think destroying the instance before destroying the cursor object.

Not according to the implementation of `vkfw::Cursor::destroy()`. That will call `createResultValue` with `Result::VKFW_ENUMERATOR(Success)`. which is unlike the `destroy` for the window/instance where those call `getError()`. 

Unless that was a mistake and it was meant to call `getError()` instead of always returning success?
created_at: 2025-04-25T17:01:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3139,7 +3139,11 @@ namespace VKFW_NAMESPACE {
 
 #ifndef VKFW_NO_SMART_HANDLE
 template <> struct VKFW_NAMESPACE::CustomDestroy<VKFW_NAMESPACE::Instance> {
-  VKFW_INLINE void destroy(Instance &instance) { static_cast<void>(instance.destroy()); }
+  VKFW_INLINE void destroy(Instance &instance) {
+    try {
+      static_cast<void>(instance.destroy());
+    } catch (...) {}
path: include/vkfw/vkfw.hpp
user: login: Cvelth
body: Yes, it looks like a bug. Could you, please, take care of it too while at it?
created_at: 2025-04-25T17:04:18Z
author_association: OWNER

PR comments:
user: login: marovira
created_at: 2025-04-25T17:12:09Z
body: I think I got everything. Let me know if I missed something!
author_association: CONTRIBUTOR
user: login: Cvelth
created_at: 2025-04-26T08:07:04Z
body: Looks good! Huge thank you for taking care of this!
author_association: OWNER