如何使用设置计数和填充数组的函数?

Joc*_*ers 1 c++ arrays vulkan

Vulkan API函数vkEnumerateInstanceExtensionProperties包含计数地址和数组地址作为参数.对于这个问题,可以忽略第一个参数.功能签名如下:

VkResult vkEnumerateInstanceExtensionProperties(
    const char*                                 pLayerName,
    uint32_t*                                   pPropertyCount,
    VkExtensionProperties*                      pProperties);
Run Code Online (Sandbox Code Playgroud)

vkEnumerateInstanceExtensionProperties文档定义的行为(上面链接):

如果pProperties参数是nullptr,则pPropertyCount参数设置为可用结构的数量.

否则,pPropertyCount应该反映pProperties传递的数组的大小并填充数组.如果数组太小,pPropertyCount则返回第一个项(并且函数返回错误代码).

我想这在C++中是一个有点常见的设计选择(或者至少在Vulkan API中),否则我不会在最初的几个小时内偶然发现它与Vulkan一起玩,所以我的问题(我在下面会问)可能更广泛地回答,但也欢迎特定的Vulkan答案.


我想检索此函数提供的所有结构.

我(松散地)遵循的Vulkan教程指定我应该使用以下'算法'来实现它:

  1. 通过第一次调用检索元素计数
  2. 分配一些数组或数据结构
  3. 使用第二个调用填充数组

在看起来像这样的代码中(教程使用向量并传递它的保留数组):

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;
Run Code Online (Sandbox Code Playgroud)

但是,这需要两次调用Vulkan API函数.我觉得这不是Vulkan API设计者的意图.是否有更好的方法来检索结构列表?

福尔康文档页面指出现有结构的数量,如果API状态变化的连续调用之间的不同.

Pau*_*ers 5

我想这是C++中一种常见的设计选择

我想说这是C中常见的[API]设计选择.C++有其他/更好的方法来做到这一点(也许返回一个std::vector适合这里).

但是,这需要两次调用Vulkan API函数.我觉得这不是Vulkan API设计者的意图.

在我看来,这正是意图,否则教程不会这么说!你还怎么做?无论如何,我不会太担心它.如果这样做很昂贵,他们就不会这样做.

Vulkan文档页面指出,如果API状态发生变化,可用结构的数量可能会在连续调用之间有所不同.

这听起来不太可能在实践中发生,只是从浏览该链接,但如果你VK_INCOMPLETE回来,你可以把结果扔掉并重新开始.

代码看起来像这样......

看起来很好 - 在C中 - 但在C++中,教程正在做什么(使用向量并传递其保留的数组)将是我的选择.我认为Vulkan API是故意用C语言编写的,因此C和C++程序都可以使用它.


编辑,在关于Vulkan选择这种API的原因的评论中解决OP的问题:

嗯,这很实用.撇开我发现的一个相当无关的细节,关于它应该是一个函数还是两个函数(谁在乎,真的?),更好的问题是谁应该分配必要的内存来保存结果和原因.

有两种基本方法:

  1. 调用者分配所需的内存,然后负责在完成后释放它.
  2. 该库分配所需的内存并提供一个额外的(可能是通用的)函数,以便在调用者完成它时释放它.

方法1在Win32 API中被广泛使用,它的优势在于您从教程中引用的示例,即(为简洁省略了错误检查):

uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
Run Code Online (Sandbox Code Playgroud)

是可能的.如果库分配内存,这更尴尬.

方法2意味着您只需要调用vkEnumerateInstanceExtensionProperties()一次,因为它可以分配所需的任何内存量并将其返回给您.

因此,方法1更灵活,方法2当然更方便,也许更高效(效率更高,完全取决于API背后的内容).

请注意:让库分配内存并且调用者释放它是不明智的选择.这样做是绝路(他们很可能是使用不同的堆,例如,想象中的混乱将使).

建议:将您计划使用的Vulkan包装在一个漂亮,友好的C++ API后面,该API在最合适的容器中返回这样的结果.如果你打算认真使用它,你会很高兴你做到了.

更新:哦,有人已经这样做了,请参阅@ Ekzuzy上面的评论.尼斯.