将 Vulkan 的 VkInstance 包装到 unique_ptr 中,无需额外的动态分配

问题描述 投票:0回答:2

我正在尝试将 VkInstance(不透明指针)包装到

unique_ptr
但似乎我不能。

...
    VkInstance instance;
    if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
        throw std::runtime_error("failed to create vulkan instance");
    }

    auto del = [](VkInstance* p) {
        DBG("release vk instance");
        vkDestroyInstance(*p, nullptr);
    };
    auto ptr = std::unique_ptr<VkInstance, decltype(del)>(instance, del);
...

错误:

no instance of constructor "std::unique_ptr<_Tp, _Dp>::unique_ptr [with _Tp=VkInstance, _Dp=lambda [](VkInstance *p)->void]" matches the argument list

我不明白为什么。 VkInstance 是一个指针,所以我传递它,删除器必须接受指向内存地址的指针,所以它仍然接收它,但仍然类型不匹配。

使用

&
取消引用并将其传递给 make_unique 会导致段错误。有道理。

我设法让它只与额外的新电话一起工作的唯一方法,就像这样:

...
    VkInstance* instance = new VkInstance;
    if (vkCreateInstance(&createInfo, nullptr, instance) != VK_SUCCESS) {
        throw std::runtime_error("failed to create vulkan instance");
    }

    auto del = [](VkInstance* p) {
        DBG("release vk instance");
        vkDestroyInstance(*p, nullptr);
    };
    auto ptr = std::unique_ptr<VkInstance, decltype(del)>(instance, del);
...

但这有点荒谬的解决方案,因为我正在动态分配一个应该放在 CPU 寄存器中并几乎立即转移到

unique_ptr
控制区域的东西。

那么,我能否以某种方式实现我想要做的事情,而无需进一步过度设计?

c++ c++17 unique-ptr vulkan
2个回答
0
投票

我认为您在将“实例”对象传递给 std::unique_ptr 构造函数时忘记了 & :

#include <iostream>
#include <memory>

struct Foo
{
};

int main()
{
    Foo f;
    auto deleter = [](Foo* f){std::cout << "deleting it!\n";};
    auto ptr = std::unique_ptr<Foo, decltype(deleter)>(&f, deleter);
}

You can try it here: https://tio.run/##RY1BDoIwFETX/FN8MTGtwQvQytJLqDGkFNIE2gq/C0I4e61E4vbNzBvl/aVTKsajsaoPjUZp3ESjrocK/mzQgxvnCiBFQRHenIMFVgFgLOFQG8t4Alni2ArI6kAOG91r0iNe8f5kKTljy5eJmrJULhBKiflWMbZDQ4eHzcW6bz19d1s5WPMO@pWITJIiaVVPs9fs5@cVO7XF/sYFrDF@AA


0
投票

问题是

VkInstance
是一个指针,而不是“指向类型”,所以基本上你应该有像
std::unique_ptr<VkInstancePointee>
这样的东西。但由于我们没有这种类型,这基本上是 Vulkan 的实现细节,可以在不通知的情况下更改,因此最好不要使用它。所以如果你想要 RAII 行为,你只需要创建包装器。像这样的东西:

class VkInstanceWrapper
{
public:
  static VkInstanceWrapper Create(const VkInstanceCreateInfo* createInfo) {
    return VkInstanceWrapper(createInfo);
  }

  VkInstanceWrapper(const VkInstanceCreateInfo* createInfo) {
    if (vkCreateInstance(createInfo, nullptr, &instance) != VK_SUCCESS) {
      throw std::runtime_error("failed to create vulkan instance");
    }
  }

  ~VkInstanceWrapper() {
    vkDestroyInstance(&instance, nullptr);
  }

  // To use in other vulkan calls
  operator VkInstance *() {
    return &instance;
  }

  // You need to delete copy constructor/assignment
  VkInstanceWrapper(const VkInstanceWrapper&) = delete;
  VkInstanceWrapper& operator=(const VkInstanceWrapper&) = delete;

  // You can either define or delete move constructor/assignment
  VkInstanceWrapper(VkInstanceWrapper&&) = delete;
  VkInstanceWrapper& operator=(VkInstanceWrapper&&) = delete;

private:
  VkInstance instance;
};
© www.soinside.com 2019 - 2024. All rights reserved.