虽然这应该是一个微不足道的问题,但到目前为止我还找不到答案。在 C API 中,有许多函数将指针和指向指针的指针作为参数。 如何正确使用智能指针作为 C API 的参数。
这是一个我想转换为使用 std::unique_ptr 的示例:
FMOD_SYSTEM* system = nullptr;
result = FMOD_System_Create(&system); // Create the main system object
FMOD_SOUND* musicStream;
result = FMOD_System_CreateSound(system,
musicStreamPath,
FMOD_CREATESTREAM,
nullptr,
&musicStream);
引用: FMOD_System_Create FMOD_System_CreateSound
我开始将智能指针声明为:
std::unique_ptr<FMOD_SYSTEM> system = nullptr;
std::unique_ptr<FMOD_SOUND> musicStream = nullptr;
如果我使用 .get(),这里是编译器错误:
cannot convert 'std::unique_ptr::pointer {aka FMOD_SOUND*}' to 'FMOD_SOUND**' for argument '5' to 'FMOD_RESULT FMOD_System_CreateSound(FMOD_SYSTEM*, const char*, FMOD_MODE, FMOD_CREATESOUNDEXINFO*, FMOD_SOUND**)' musicStream.get());
^
最佳答案
您的问题是因为 C API 希望您将 指针的地址传递给 FMOD_SYSTEM
,以便 API 可以用结果填充该指针— 即,它将 FMOD_SYSTEM*
作为输出参数。
在 C++ 中,惯用的方法是将一个引用传递给一个(智能?)指向 FMOD_SYSTEM
的指针,即 C API 所在的位置
FMOD_RESULT FMOD_System_Create(FMOD_SYSTEM **system);
FMOD_SYSTEM *system;
result = FMOD_System_Create(&system);
C++ API 是
FMOD_RESULT FMOD_System_Create(std::unique_ptr<FMOD_SYSTEM> &system);
std::unique_ptr<FMOD_SYSTEM> system;
result = FMOD_System_Create(system);
但是,这个 C++ API 有一个大问题!问题是创建 FMOD_SYSTEM
和将它包装在unique_ptr
中是不同的问题,不应该像这样混在一起。例如,如果我正在用线程做一些聪明的事情并且真的需要我的 FMOD_SYSTEM
由 shared_ptr
而不是简单的 unique_ptr
管理怎么办?我必须创建一个 unique_ptr
以作为输出参数传递,然后 std::move
将其放入 shared_ptr
之后?这既丑陋又(微观)低效。
std::unique_ptr<FMOD_SYSTEM> fake_system;
result = FMOD_System_Create(fake_system);
std::shared_ptr<FMOD_SYSTEM> system(std::move(fake_system));
答案是要认识到问题的根源在于参数本身,而解决方案是值语义。我们想要编写的惯用 C++ 语法是
auto system = std::make_unique<fmod_system>();
我们获得该语法的方法是将 C API 的原始指针包装在值类中:
class fmod_system {
FMOD_SYSTEM *ptr;
fmod_system() {
auto result = FMOD_System_Create(&ptr);
if (result != FMOD_OK) {
ptr = nullptr;
throw something;
}
}
fmod_system(fmod_system&&) = default;
fmod_system& operator=(fmod_system&&) = default;
fmod_system(const fmod_system&) = delete;
fmod_system& operator=(const fmod_system&) = delete;
~fmod_system() {
auto result = FMOD_System_Release(ptr);
assert(result == FMOD_OK); // destructors shouldn't throw: use your best judgment here
}
};
事实上,此时我们的调用者可以放弃 unique_ptr
混淆并简单地写
fmod_system system;
除非出于某种原因他们真的需要额外的指针语义层。
关于c - 使用 C++11 智能指针作为 C 函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27680981/