C++ 如何使用设置计数和填充数组的函数?
Vulkan API函数包含计数地址和数组地址作为参数。对于这个问题,可以忽略第一个参数。功能签名如下:C++ 如何使用设置计数和填充数组的函数?,c++,arrays,vulkan,C++,Arrays,Vulkan,Vulkan API函数包含计数地址和数组地址作为参数。对于这个问题,可以忽略第一个参数。功能签名如下: VkResult vkEnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionPropertie
VkResult vkEnumerateInstanceExtensionProperties(
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
vkEnumerateInstanceExtensionProperties的行为,如文档所定义(如上链接):
如果pProperties
参数为nullptr
,则pPropertyCount
参数设置为可用结构的数量
否则,pPropertyCount
应反映传递的pProperties
数组的大小,并填充该数组。如果数组太小,则返回第一个pPropertyCount
项(函数返回错误代码)
我想这是一个在C++中有点常见的设计选择(或者至少在VulkAN API中),否则我在Vulkan的最初几小时就不会碰到它,所以我的问题(下面我问)可能更一般地回答,但是Vulkan特有的答案也很受欢迎。
我想检索这个函数提供的所有结构
I was(松散地)following指定我应该使用以下“算法”来实现这一点:
通过第一次调用检索元素计数
分配一些数组或数据结构
用第二次调用填充数组
在类似这样的代码中(本教程使用向量并传递其保留数组):
但是,这需要调用Vulkan API函数两次。我觉得这不是Vulkan API设计者的意图。有没有更好的方法来检索结构列表
声明如果API状态更改,则连续调用之间可用结构的数量可能会有所不同
我想这是C语言中比较常见的设计选择++
我想这是一个普通的[API ]设计选择,在C++中有其他更好的方法来完成这一任务(也许返回一个<代码>:ST::vector < /代码>这里是合适的)。
但是,这需要调用Vulkan API函数两次。我觉得这不是Vulkan API设计者的意图
在我看来,这正是我的意图,否则教程不会这么说!否则你会怎么做?无论如何,我不会太担心的。如果那样做很昂贵,他们就不会那样做
Vulkan文档页面指出,如果API状态发生变化,则连续调用之间可用结构的数量可能会有所不同
这听起来不太可能在实践中发生,只需浏览一下该链接,但如果您得到VK_complete
返回,您可以扔掉结果,重新开始
在代码中看起来像这样
这看起来很好——在C -但是C++中,教程正在做什么(使用向量并通过它的保留数组)将是我的选择。我想,VulcAN API是故意用C编写的,所以C和C++程序都可以利用它。
编辑,以解决OP在评论中关于Vulkan为什么选择这种API风格的问题:
嗯,这很实用。抛开我发现的一个非常不相关的细节,关于它应该是一个函数还是两个函数(谁在乎,真的?),更好的问题是谁应该分配必要的内存来保存结果以及为什么
有两种基本方法:
调用者分配所需的内存,然后负责在完成时释放内存
该库分配所需的内存,并提供一个附加的(可能是通用的)函数,以便在调用者使用完内存后释放它
方法1在Win32 API中广泛使用,它的优点是您从教程中引用的示例,即(为简洁起见,省略了错误检查):
uint32\u t extensionCount=0;
vkEnumerateInstanceExtensionProperties(nullptr和extensionCount、nullptr);
std::向量扩展(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr,&extensionCount,extensions.data());
这是可能的。如果库分配内存,这就更麻烦了
方法2意味着您只需要调用vkEnumerateInstanceExtensionProperties()
一次,因为它可以分配所需的内存量并返回给您
因此,方法1更灵活,方法2当然更方便,也许更高效(效率有多高完全取决于API背后的内容)
请注意:让库分配内存并让调用方释放内存不是一个明智的选择。这样做是走向毁灭的道路(他们可能使用不同的堆,例如,想象一下会造成的混乱)
<强>建议:将你打算使用的Vulkan的一部分包裹在一个友好、友好的C++ API后面,这样在最合适的容器中返回这样的结果。如果你打算认真使用它,你会很高兴你做的。
更新:哦,已经有人这么做了,请看上面@Ekzuzy的评论。很好。@Jochem只是一个提醒-擦亮我的答案,你可能想再看一眼。谢谢,这正是我想要的答案!你知道C风格API设计使用此模式的原因吗?对我来说,似乎违反了规则单一责任原则;该函数既涉及数据的传递,也涉及数据的计数。至少,一个*-Count
(后缀)函数的唯一目的是报告元素的数量。@jochemkuippers我认为这种设计选择是为了减少(不必要的)元素的数量API公开的函数。至于责任-获取所需的内存是开发人员的责任
uint32_t count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); // only retrieve count
VkExtensionProperties* list = new VkExtensionProperties[count];
vkEnumerateInstanceExtensionProperties(nullptr, &count, list); // now populate the array
// after use
delete[] list;
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());