In most cases, you can get away with assigning VK_NULL_HANDLE to any handle defined by VK_DEFINE_HANDLE(object) or VK_DEFINE_NON_DISPATCHABLE_HANDLE(object), but std::exchange() fails to set this value in almost all cases.
In most situations I have to call std::exchange(m_dispatchableHandle, nullptr) and std::exchange(m_nonDispatchableHandle, nullptr)
However, on x86, nullptr is invalid due to the redefinition of VK_DEFINE_NON_DISPATCHABLE_HANDLE. I must use std::exchange with NULL, 0, or (finally) VK_NULL_HANDLE.
My question: in following the VK_DEFINE_HANDLE macro patterns, should there not be two null handle macros defined like the following?
#define VK_NULL_HANDLE nullptr
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_NON_DISPATCHABLE_NULL_HANDLE nullptr
#else
#define VK_NON_DISPATCHABLE_NULL_HANDLE 0
#endif
If nothing else, it seems like #define VK_NULL_HANDLE nullptr would have more utility in general.
I may be misunderstanding how the API is supposed to be used, so I'm sharing the trouble code in question: a move constructor that transfers handles and fills the old object with NULL or VK_NULL_HANDLE. By carefully managing ownership, the class can be designed simply and handle vkDestroy* et. al. in its destructor.
class RenderContext
{
public:
RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx);
RenderContext(const RenderContext& other) = delete;
RenderContext& operator=(const RenderContext& other) = delete;
RenderContext(RenderContext&& other) noexcept;
RenderContext&& operator=(RenderContext&& other) = delete;
~RenderContext();
private:
VkDevice _device;
VkCommandPool _gCmdPool;
VkCommandPool _pCmdPool;
VkQueue _gQueue;
VkQueue _pQueue;
};
RenderContext::RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx) :
_device(VK_NULL_HANDLE),
_gCmdPool(VK_NULL_HANDLE),
_pCmdPool(VK_NULL_HANDLE),
_gQueue(VK_NULL_HANDLE),
_pQueue(VK_NULL_HANDLE)
{
// ...
}
RenderContext::RenderContext(RenderContext&& other) noexcept :
_device(std::exchange(other._device, nullptr)),
_gCmdPool(std::exchange(other._gCmdPool, VK_NULL_HANDLE)),
_pCmdPool(std::exchange(other._pCmdPool, VK_NULL_HANDLE)),
_gQueue(std::exchange(other._gQueue, nullptr)),
_pQueue(std::exchange(other._pQueue, nullptr))
{}
RenderContext::~RenderContext()
{
vkDestroyCommandPool(_device, _pCmdPool, nullptr);
vkDestroyCommandPool(_device, _gCmdPool, nullptr);
vkDestroyDevice(_device, nullptr);
}
Templates in C++ require precise type, not just compatible one, to properly instantiate. As such C's NULL (defined as 0) might be a problem. 0 might also be a problem as it is int, not uint64_t, which is the ABI of Non-dispatchable Handles (which can be stored in 64 bit pointer to get some type safety out of C). This is not new when dealing with C libraries from C++ (or generally).
Rest is design questions and suggestions adressed at authors, and as such unsuitable for StackOverflow. The issue tracking system is available at https://github.com/KhronosGroup/Vulkan-Docs/issues. On the face, your suggestion makes sense to me. They probably do not want to make it pervasive, but additionally, it might be a case for doing #ifdef __cplusplus #define VK_NULL_HANDLE nullptr.
Alternatively, there is Vulkan-Hpp, which is supposed expose more C++-istic bindings to Vulkan.
Proper way currently to call the template function would be std::exchange(m_nonDispatchableHandle, decltype(m_nonDispatchableHandle)(VK_NULL_HANDLE));.
In most cases, VK_NULL_HANDLE can be assigned to any handle defined by VK_DEFINE_HANDLE(object) or VK_DEFINE_NON_DISPATCHABLE_HANDLE(object)
Wrong. You can get away with it because C and C++ let you. But the Vulkan specification is very clear:
The reserved values VK_NULL_HANDLE and NULL can be used in place of valid non-dispatchable handles and dispatchable handles, respectively
That is, VK_NULL_HANDLE is only for non-dispatchable handles. That the C/C++ languages allow you to assign the value of VK_NULL_HANDLE to a dispatchable handle is merely a function of the language, and the behavior for Vulkan itself is not defined.
You should never be trying to std::exchange between a dispatchable handle and a non-dispatchable handle, just as you should never be trying to std::exchange between two distinct types.
Related
I have a C program which I need to connect to a C++ API. I asked on here and was given great advice, leading to creating a "wrapper".
So, in the API there is a type called "APIName::ReturnCode", and I wanted to create a C equivalent, so I've done the following:
In c_api.h:
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void* API_ReturnCode_t;
EXTERNC API_ReturnCode_t api_returncode_init();
EXTERNC void api_returncode_destroy(API_ReturnCode_t rc);
#undef EXTERNC
in c_api.cpp:
#include "c_api.h"
#include "/path/to/api/api.h"
API_ReturnCode_t api_returncode_init() {
return new APIName::ReturnCode;
}
void api_returncode_destroy(API_ReturnCode_t untyped_ptr) {
APIName::ReturnCode* typed_ptr = static_cast< APIName::ReturnCode*>(untyped_ptr);
delete typed_ptr;
}
So I compile that into a library and include it in my main program, and I can use things like:
API_ReturnCode rc;
to define a variable.
However, my next issue is how to define enumerated types in a similar way. So, the api has the following definition for error codes:
namespace APIName {
typedef enum ReturnCode_enum ReturnCode;
enum ReturnCode_enum {
RC_OK , // success
RC_ERROR , // general error
RC_NOT_AVAILABLE , // feature is not available
};
}
How do I recreate this in my wrapper so that I can do something like this in my code:
API_ReturnCode rc = API_RC_OK;
Thank you.
So after some clarification, my original answer is no longer applicable -- but is still retained below this answer.
Since the original C++ API cannot be altered in any way, you are much more limited in your available options.
You want to be able to do:
API_ReturnCode rc = API_RC_OK;
But rc is an opaque type (void*) that requires being destroyed with api_returncode_destroy -- so this won't be possible in an easy and sane way (not without confusing who owns the API_RC_OK calls). The biggest issue is that if we could produce an API_RC_OK instance, it leads to questionable ownership. For example:
API_ReturnCode rc = API_RC_OK;
api_returncode_destroy(rc); // is this good? is 'API_RC_OK' a resource that needs deleting?
And it gets more confusing in more complicated expressions.
Since the APIName::ReturnCode_enum type is just a classic C-style enum, which is implicitly convertible to an int, your best-bet here would be to try to preserve the int-like property by making API_ReturnCode_t's definition be:
typedef int API_ReturnCode_t;
Then any of the C++-wrapped calls can propagate the values as this int
Unfortunately to be able to receive these values on the other side, you will need to duplicate some effort here by manually re-creating these constants in some way. There are a few approaches that come to mind, all with pros and cons.
The inconvenient truth here is that, because you're trying to expose values defined in C++ in C, you'll need to somehow re-encode this on the other side in some way. You can't simply include the C++ header and use it in C, since they are different languages and C++ contains features that C doesn't understand.
1. Use extern constants
One possible approach is to use extern const values that get defined in the source from the underlying values, so you aren't stuck duplicating the values themselves. For example:
c_api.h
EXTERNC extern const API_ReturnCode_t API_RC_OK;
EXTERNC extern const API_ReturnCode_t API_RC_ERROR;
EXTERNC extern const API_ReturnCode_t API_RC_NOT_AVAILABLE;
c_api.cpp
extern "C" {
const API_ReturnCode_t API_RC_OK = APIName::RC_OK;
const API_ReturnCode_t API_RC_ERROR = APIName::RC_ERROR;
const API_ReturnCode_t API_RC_NOT_AVAILABLE = APIName::RC_NOT_AVAILABLE;
} // extern "C"
The good thing with this approach is that you aren't stuck manually setting API_RC_OK to 0, and API_RC_ERROR to 1, etc -- so these values are not strongly coupled.
The thing to watch out for is that these extern constants would not be (safely) usable from other objects during static initialization, since it's not guaranteed when these values will be set. If you aren't doing much static initialization, this shouldn't be of any concern.
2. Just duplicate the effort
If the enum is not large, and not likely to grow much larger, the obvious simple approach is to just do:
#define API_RC_OK 0
#define API_RC_ERROR 1
#define API_RC_NOT_AVAILABLE 2
or some equivalent thereof. The pro is that this can be used anywhere, compared to extern constants. The obvious con here is that the wrapper is strongly coupled to the wrapped library. If this is a large enumeration, or an enum that is likely to change often / regularly -- this is approach is probably not the best.
3. Define a possibly-orthogonal enumeration
One other option is to define an orthogonal enumeration instead. This requires re-defining the enum cases that you care about, and translating them through a separate function call. This results in more effort -- so depending on what you're doing, this may not be the best case.
c_api.h
typedef enum {
API_RC_OK,
API_RC_ERROR,
API_RC_NOT_AVAILABLE,
/* other states? */
} API_ReturnCode_t;
**c_api.cpp
API_ReturnCode_t to_return_code(APIName::ReturnCode rc)
{
switch (rc) {
case APIName::RC_OK: return API_RC_OK;
case APIName::RC_ERROR: return API_RC_ERROR;
case APIName::RC_NOT_AVAILABLE: return API_RC_NOT_AVAILABLE;
}
return API_RC_NOT_AVAILABLE;
}
In your wrapper code, anywhere you receive an APIName::ReturnCode you would now translate to an API_ReturnCode_t before returning back to the C caller.
The nice thing about this approach is that the enumerators no longer need to be in-sync, and that you can restrict the enum cases that you want to abstract out (assuming you don't want 1-1 mapping).
This also presents an easier way to upgrade in the future to different versions of the C++ library, since everything is internalized by the translation function. If the C++ library introduces new states, you can choose to coalesce some of those values together in a way that may make it more consumable by the C client.
The obvious downside with this approach is that it takes more work, since you're defining a separate hierarchy and a translation system that will be quite similar in the beginning. It's more work up-front for a higher return later on.
Old Answer
There is nothing specific to C++ about your ReturnCode_enum class. It's actually written in a more legacy-C++ style (e.g. not using enum class for scoping), which makes it usable in C directly.
So why not define the enum in the c_api.h header file instead, and use it in your C++ as well? This may require changing your opaque handle definition depending on what is stored in it; but this way you would have exactly 1 definition of the enumeration.
You can bring the C symbol into C++ namespaces using either typedef or using aliases, which allow a more C++-esque discovery of the values.
In c_api.h:
enum Api_ReturnCode_enum {
RC_OK , /* success */
RC_ERROR , /* general error */
RC_NOT_AVAILABLE , /* feature is not available */
};
/*
or 'typedef enum { ... } Api_ReturnCode_enum;' if you want don't want to specify
'enum' every time in C
*/
In your C++ API:
#include "c_api.h"
namespace APIName { // bring it into this namespace:
// Alias the "Api_" prefixed enum to be more C++ like
typedef Api_ReturnCode_enum ReturnCode;
// alternative, in C++11 or above:
// using ReturnCode = Api_ReturnCode_enum;
}
I wouldn't hide error code enums in opaque handles.
Create a new enum and convertion functions in the c_api.cpp file
c_api.h
typedef enum {
RC_OK,
RC_ERROR,
RC_NOT_AVAILABLE
} ReturnCode_copy;
ReturnCode_copy some_function(...);
c_api.cpp
static ReturnCode_copy convert(APIName::ReturnCode code) {
switch(code) {
//return correct ReturnCode_copy
}
}
ReturnCode_copy some_function(...) {
auto code = //some api function returning error code
return convert(code);
}
or you could be naughty and just copy the values directly in your new enum and just static_cast directly without the convert function.
In the Microsoft implementation of guidelines support library I see the following piece of code:
template<class T>
class not_null {
...
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr explicit not_null(U&& u) : ptr_(std::forward<U>(u)) {
Expects(ptr_ != nullptr);
}
...
constexpr T get() const {
Ensures(ptr_);
return ptr_;
}
...
T ptr_;
}
All the constructors of gsl::not_null which take possibly pointers check these pointers are not null, but we still check stored value of pointer (ptr_) against null on each dereference. Why do we have this check, given that in C++ we typically don't pay for what we don't need?
UP: Ensures is implemented as follows (with default flags):
#define GSL_LIKELY(x) (!!(x))
...
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
...
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
The comments are already giving the idea why removing null check from not_null::get() is not desirable. The main problem is that the change allows dereferencing a smart pointer after move.
For examples, see the following discussion on a PR that enables usage of not_null<unique_ptr> and how the change is incompatible with removing the null check from not_null::get()
https://github.com/Microsoft/GSL/pull/675
As for performance concerns, compiler optimizer should be able to remove many of the null checks, but not all, of course. If some checks are not removed but seem to be removable, we should fix compiler optimizations.
I'd like to keep my code compilable both on legacy C++ (C++ code using "NULL") and new C++11 standard (C++ code using "nullptr")
I'm using GCC, but planning to recompile the whole codebase also for VS when I'll finish most important things.
Should I expect both GCC and VS will do something like
#define NULL nullptr
Or Is better I'll do that myself (using of course a different name, where MY_LIB will be replaced by my library suffix)?
#ifndef nullptr
#define MY_LIB_NULL NULL
#else
#define MY_LIB_NULL nullptr
#endif
What I want to achieve is code that compiles regardless of wich C++11 features have been implemented or not (and since i'm not using templates, there are very few of them).
For example the keywords "override" and "final" are already done.
MY_LIB_OVERRIDE //macro, defines to "override" if c++11 is present.
MY_LIB_FINAL //macro, defines to "final" if c++11 is present.
I'm asking the question because I know the "nullptr" question is a bit strange, so maybe just doing the same I already did for override and final, is wrong. Needs opinions about that. Any help is wellcome.
You could probably create a "false" my_nullptr of type my_nullptr_t the following way:
const class my_nullptr_t
{
public:
/* Return 0 for any class pointer */
template<typename T>
operator T*() const
{
return 0;
}
/* Return 0 for any member pointer */
template<typename T, typename U>
operator T U::*() const
{
return 0;
}
/* Safe boolean conversion */
operator void*() const
{
return 0;
}
private:
/* Not allowed to get the address */
void operator&() const;
} my_nullptr = {};
This works with C++03 and C++11 and should always be safe, whichever C++11 features are implemented. That solution was actually already discussed in this topic that proposed a version of nullptr_t based on the Official proposal.
NULL is a macro that expands to a null pointer constant. It still works just like it used to. Code that has to work with non-C++11 compilers should use NULL.
I think following will works:
#include <cstddef>
#ifndef MY_LIB_NULL
#ifndef NULL //check for NULL
#define MY_LIB_NULL nullptr
#else
#define MY_LIB_NULL NULL ///use NULL if present
#endif
#endif
basically I check for "NULL". wich is a macro and can be checked, until the compiler is shipped with that macro (likely to be), than it's valid using the macro, when compiler will only provides "nullptr" and no longer have NULL then nullptr is used (maybe in a far future, but seems we can happily continue to use NULL!)
I think that's safer than redefining "nullptr" (like most people trying to do)
Imaging a class which is doing the following thing
class AClass
{
AClass() : mode(0) {}
void a()
{
if (mode != 0) throw ("Error mode should be 0");
// we pass the test, so now do something
...
mode = 1;
}
void b()
{
if (mode != 1) throw("Error mode should be 1");
// we pass the test, so now do something
...
}
int mode;
};
The class contains many methods (easily than 20) and for each one of these methods we need to do a check on the value of mode which is obviously a lot of code duplication. Furthermore, we can identify two categories of methods, those who will throw an error if mode !=0 and those who will throw an error if mode != 1. Could it somehow be possible to group these methods in two categories (category A = method who throw an error if mode != 0) and category B for method who throw an error if mode != 1)?
EDIT: Looking at the current answers I realise the way I formulate the question and the problem is probably not clear enough. What I want to avoid is to have to call for a function in each method of the class. Whether we write code at the beginning of the methods or put this code in a function and call this function is not the problem. The question is whether we can avoid this all together. Whether there is a technique that would help to automatically check whether the call to a method of a class is valid depending on some context.
AClass is actually an API in the context of my project. a(), b(), etc. are some functions that the programmer can call if she/he wants to use the API however some of these methods can only be called in some precise order. For example you can see in the code that a() sets mode = 1. So the programmer could do something like this:
a(); // mode = 0 so it's good
b(); // mode = 1 so it's good
but this code needs to fail (it will compile of course but at execution time I need to throw an error mentioning that the context in which b() was called was wrong.
b(); // mode 0 so it won't work
a(); // it will compile but throw an exception
I tried to see if any pattern could work for doing this but couldn't find anything at all. It seems impossible to me and I believe the only option is really to write the necessary code. Could anyone though suggest something? Thank you very much.
Just add private member functions:
void assert_mode_0() {
assert_mode(0);
}
void assert_mode_1() {
assert_mode(1);
}
void assert_mode(int m) {
if (mode != m)
throw msg[m];
}
with a suitable definition of msg, of course.
Aside from implementing the check in a dedicated method (a great suggestion), you could also consider decomposing the behavior in AClass into two distinct classes, or delegate the specific portion to a new pair of classes. This seems especially appropriate if the mode is invariant for an instance (as it is in the example).
Well I guess the simplest solution would be defining a macro or some inline function like this:
#define checkErrorMode0(x) \
if ((x) != 0) throw ("Error mode should be 0");
#define checkErrorMode1(x) \
if ((x) != 1) throw ("Error mode should be 1");
// or, probably within your class
inline void checkErrorMode0(int x){
if ( x != 0 ) throw ("Error mode should be 0");
}
inline void checkErrorMode1(int x){
if ( x != 1 ) throw ("Error mode should be 1");
}
So you could simply call one of these methods inside of the functions that require them.
But most likely there is a more elegant workaround for what you want to do.
After looking into the problem a bit more, it seems that the closest helpful answer is (by Nick):
Try looking into Aspect Oriented Software Development en.wikipedia.org/wiki/Aspect-oriented_software_development – Nick
The Wikipedia page is not easy to read and doesn't provide a C++ example, so it stays very abstract at first, but if you search for Aspect Oriented Programming and C++ you will find links with examples.
The idea behind it (and it just a very quick summary) is to find a way of adding "services" or "functionalities" to a class. These services can notably be added at compile time through the use of templates. This is what I was intuitively experimenting with as an attempt at solving my problem, and I am glad to see this technique has been around for many years.
This document is a good reference:
Aspect-Oriented Programming & C++ By Christopher Diggins, August 01, 2004.
And I found this link with example useful to understand the concept:
Implementing Aspects using Generative Programming by Calum Grant.
I've recently posted a general question about RAII at SO.
However, I still have some implementation issues with my HANDLE example.
A HANDLE is typedeffed to void * in windows.h. Therefore, the correct shared_ptr definition needs to be
std::tr1::shared_ptr<void> myHandle (INVALID_HANDLE_VALUE, CloseHandle);
Example 1 CreateToolhelp32Snapshot: returns HANDLE and works.
const std::tr1::shared_ptr<void> h
(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), CloseHandle);
As I use void in the definition (what is the correct way?) problems go on, when I try to call some more winapi commands with this pointer. They functionally work, but are ugly and I am sure that there has to be a better solution.
In the following examples, h is a pointer which was created via the definition at the top.
Example 2 OpenProcessToken: last argument is a PHANDLE. medium ugly with the cast.
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
(PHANDLE)&h);
Example 3 Process32First: first argument is a HANDLE. REALLY ugly.
Process32First(*((PHANDLE)&h), &pEntry);
Example 4 simple comparison with a constant HANDLE. REALLY ugly.
if (*((PHANDLE)&h) == INVALID_HANDLE) { /* do something */ }
What is the correct way to create a proper shared_ptr for a HANDLE?
Example 1 is OK
Example 2 is wrong. By blindly casting to PHANDLE, the shared_ptr logic is bypassed. It should be something like this instead:
HANDLE h;
OpenProcessToken(...., &h);
shared_ptr<void> safe_h(h, &::CloseHandle);
or, to assign to a pre-exising shared_ptr:
shared_ptr<void> safe_h = ....
{
HANDLE h;
OpenProcessToken(...., &h);
safe_h.reset(h, &::CloseHandle);
}//For extra safety, limit visibility of the naked handle
or, create your own, safe, version of OpenProcessToken that returns a shared handle instead of taking a PHANDLE:
// Using SharedHandle defined at the end of this post
SharedHandle OpenProcess(....)
{
HANDLE h = INVALID_HANDLE_VALUE;
::OpenProcessToken(...., &h);
return SharedHandle(h);
}
Example 3: No need to take these detours. This should be ok:
Process32First(h.get(), ...);
Example 4: Again, no detour:
if (h.get() == INVALID_HANDLE){...}
To make things nicer, you could typedef something like:
typedef shared_ptr<void> SharedHandle;
or better yet, if all handles are to be closed with CloseHandle(), create a SharedHandle class wrapping a shared_ptr and automatically providing the right deleter:
// Warning: Not tested. For illustration purposes only
class SharedHandle
{
public:
explicit SharedHandle(HANDLE h) : m_Handle(h, &::CloseHandle){};
HANDLE get()const{return m_Handle.get();}
//Expose other shared_ptr-like methods as needed
//...
private:
shared_ptr<void> m_Handle;
};
Don't bother with shared_ptr for that, use ATL::CHandle.
Here is why:
When you see CHandle you know that it's a RAII wrapper for a handle.
When you see shared_ptr<void> you don't know what it is.
CHandle doesn't make an ownership shared (however in some cases you may want a shared ownership).
CHandle is a standard for a windows development stack.
CHandle is more compact than shared_ptr<void> with custom deleter (less typing/reading).
Take a look at boost 2: shared_ptr wraps resource handles
Here is my alternative, which is quite nice except you need to dereference always after .get() and requires a functor or lambda:
template<typename HandleType, typename Deleter>
std::shared_ptr<HandleType> make_shared_handle(HandleType _handle, Deleter _dx)
{
return std::shared_ptr<HandleType>(new HandleType(_handle), _dx);
}
then:
auto closeHandleDeleter = [](HANDLE* h) {
::CloseHandle(*h);
delete h;
};
std::shared_ptr<HANDLE> sp = make_shared_handle(a_HANDLE, closeHandleDeleter);
f_that_takes_handle(*sp.get());
what I like most about this is there is no extra work to have access to this:
std::weak_ptr<HANDLE> wp = sp; // Yes. This could make sense in some designs.
and of course, the helper function works with any handle type of the likes.