Const correctness when using vulkan

Let’s look at the vulkan.hpp-headers, and consider the method vk::CommandBuffer::drawIndexed as an example. Clearly this method changes the state of the command-buffer that is referenced by by the VkCommandBuffer handle. Has anyone got some insight as to what was the rationale behind making such a method const?
Also, since VkHandles are passed around by value, having a construct such as for example void onlyReadXY(VkPhysicalDevice const physical_device) makes no sense since one can just copy away the constness.
Is there any way I can separate vulkan-functions that only read internal data from functions that also modify internal data, or does the api make no promises there?
To the last question, would not the aforementioned method from the vulkan.hpp have to make everything non-const in that case?
I know that these are technically multiple questions, however I think they are all related, and the answer to one may imply the answer to the other.

Thanks in advance for any insight, or references.

Kind regards,

It’s shallow const, not deep const.

The C++ Vulkan header is not trying to pretend that it isn’t wrapping the API. It doesn’t hide from you the fact that there’s an underlying API or how that API works. It’s just providing a C++ view of the API.

All C++ Vulkan objects are references to the actual object, just as they are in C. As such, any const qualifications apply to how the function deals with the reference, not the data being referenced.

Such a thing would generally be quite pointless. There aren’t that many functions that only read data, and you generally only use such functions during setup (finding out how much storage is available, which image/buffer formats are supported, etc). All other functions manipulate the internal state of at least one Vulkan object.

Also, Vulkan functions that manipulate object data don’t tend to be coy about what they manipulate. If they’re going to modify the state of some object, that’s usually the thing that function does. vkUpdateDescriptorSets is used to… update descriptor sets. Functions of the form vkCmd* issue commands to a command buffer. Etc.

As such, there’s little chance that a user will become confused about which objects are being modified in an operation.

Thank you for your detailed answer.
“Shallow const” is not what I would define as const in my own code, but considering the nature of the opaque VkHandles, and the clear separation of application-developer-interface, and driver-implementation, I can see why it is treated that way in the .hpp-headers.

Funny that you would mention the vkUpdateDescriptorSets, since that is a function which I would give as an example for objects only being used for reading, not mutating. The VkDescriptorBufferInfo contains a VkBuffer, yet that buffer, as far as I’m aware, is not mutated when updating a descriptor-set with it. This is one instance where I would have liked to be able to hand out a “const-version” of the buffer.

However, now that I’m thinking about it, a shader may modify the contents of a uniform/storage-buffer, and the descriptor-update would be the middleman that would enable it to do so, so that example may be invalid as well…

All in all I can work with the “shallow-constness”. I guess when passing around vulkan-handles I will adapt this definition of “const” while maintaining a “deep-const” for the rest of my objects…

Thanks for clarifying these things for me! :slight_smile: