我正在尝试将 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
控制区域的东西。
那么,我能否以某种方式实现我想要做的事情,而无需进一步过度设计?
我认为您在将“实例”对象传递给 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);
}
问题是
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;
};