NVIDIA TensorRT 对象,例如 nvinfer1::IRuntime
和nvinfer1::ICudaEngine
不能直接存储在 std::unique_ptr<>
中。相反,他们有一个 destroy()
必须调用的方法。
因此,要实现此目的,您必须使用如下删除器:
#include <NvInfer.h>
#include <cuda.h>
template<typename T>
struct NVIDIADestroyer
{
void operator()(T * t)
{
t->destroy();
}
};
template<typename T>
using NVIDIAUniquePtr = std::unique_ptr<T, NVIDIADestroyer<T>>;
而不是 std::unique_ptr<T>
,然后使用 NVIDIAUniquePtr<T>
.
到目前为止,效果很好。然后我在清理代码时尝试做的就是用 lambda 替换删除器,这样我就可以跳过定义 NVIDIADestroyer
结构。但我不知道该怎么做。我的想法是这样的:
template<typename T>
using NVIDIAUniquePtr = std::unique_ptr<T, [](T * t)
{
t->destroy();
}>;
但这会导致以下错误消息:
TRT.hpp:52:45: error: lambda-expression in template-argument
using NVIDIAUniquePtr = std::unique_ptr<T, [](T * t)
^
TRT.hpp:55:2: error: template argument 2 is invalid
}>;
^
有办法实现这个功能吗?
最佳答案
自 C++11 以来,使用定义为 struct
或 class
的无状态删除器具有零运行时和空间开销,没有比这更好的了。
对删除器使用函数模板而不是类模板,无需指定删除器类模板参数,也无需包含 CUDA 头文件。
删除器函数上的noexcept
可能会导致调用代码更小。因为在 noexcept
调用周围的调用者中不需要编译器生成的堆栈展开代码。 (GNU C++ 标准库 ~unique_ptr()
无条件地是 noexcept
,但 C++ 标准并不要求这样做。GNU C++ 标准库可能会为您做到这一点,原因正是如此太糟糕了,出于 ABI 稳定性原因(我们在 C++ 中无法拥有好东西的第一个原因),编译器不会自动推导和应用 noexcept
,理论上可以用显式的用户提供的覆盖noexcept
规范,但这本身就是一个大主题。)
自 C++17 起,无捕获 lambda 闭包也可以用作零开销的删除器:
#include <memory>
#include <iostream>
// C++11
struct Deleter { template<class P> void operator()(P p) noexcept { p->destroy(); } };
template<class T> using P11 = std::unique_ptr<T, Deleter>;
// C++17
constexpr auto deleter = [](auto p) noexcept { p->destroy(); };
template<class T> using P17 = std::unique_ptr<T, decltype(deleter)>;
int main() {
std::cout << sizeof(void*) << '\n';
std::cout << sizeof(P11<void>) << '\n';
std::cout << sizeof(P17<void>) << '\n';
}
使用 -std=c++17
编译输出:
8
8
8
关于c++ - 如何将 lambda 与模板化 std::unique_ptr 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65938991/