c之使用 C++11 智能指针作为 C 函数参数

dudu 阅读:95 2025-06-02 22:19:02 评论:0

虽然这应该是一个微不足道的问题,但到目前为止我还找不到答案。在 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_SYSTEMshared_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++
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号