首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用C++11智能指针作为C函数参数

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

Stack Overflow用户
提问于 2014-12-28 21:56:48
回答 3查看 1.6K关注 0票数 2

虽然这应该是一个微不足道的问题,但到目前为止,我还是找不到答案。在APIs中,有许多函数将指针和指向指针的指针作为参数。如何使用正确的智能指针作为C API的参数。

下面是一个我想转换为使用std::unique_ptr的示例:

代码语言:javascript
复制
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);

参考资料:创建 CreateSound

我开始将智能指针声明为:

代码语言:javascript
复制
std::unique_ptr<FMOD_SYSTEM> system = nullptr;
std::unique_ptr<FMOD_SOUND> musicStream = nullptr;

如果我使用.get(),下面是编译器错误:

不能将参数'5‘的'std::unique_ptr::pointer {aka FMOD_SOUND*}’转换为'FMOD_SOUND**‘到'FMOD_RESULT FMOD_System_CreateSound(FMOD_SYSTEM*,const char*,FMOD_MODE,FMOD_CREATESOUNDEXINFO*,FMOD_SOUND**)’musicStream.get(); ^

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-28 22:47:51

您的问题在于,can希望您将指针的地址传递给FMOD_SYSTEM,以便API可以用结果填充该指针--也就是说,它将FMOD_SYSTEM*作为输出参数。

在C++中,这样做的惯用方法是将引用传递给(smart?)指向FMOD_SYSTEM的指针,即C位于

代码语言:javascript
复制
FMOD_RESULT FMOD_System_Create(FMOD_SYSTEM **system);

FMOD_SYSTEM *system;
result = FMOD_System_Create(&system);

C++ API将是

代码语言:javascript
复制
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中是不同的问题,不应该像这样混在一起。例如,如果我在线程处理方面做了一些聪明的事情,并且真的需要由shared_ptr而不是简单的unique_ptr来管理我的unique_ptr,该怎么办?我必须创建一个unique_ptr作为out参数传递,然后在std::move之后将其转换为一个shared_ptr?这既丑陋又(微观)低效。

代码语言:javascript
复制
std::unique_ptr<FMOD_SYSTEM> fake_system;
result = FMOD_System_Create(fake_system);
std::shared_ptr<FMOD_SYSTEM> system(std::move(fake_system));

答案是要认识到问题的根源在于参数本身,而解决方案是值语义。我们想要编写的惯用C++语法是

代码语言:javascript
复制
auto system = std::make_unique<fmod_system>();

获得这种语法的方法是将C的原始指针封装在值类中:

代码语言:javascript
复制
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混淆,只需编写

代码语言:javascript
复制
fmod_system system;

除非出于某种原因他们真的需要额外的一层指针语义。

票数 4
EN

Stack Overflow用户

发布于 2014-12-29 10:01:35

总的来说,我不认为将Class与智能指针混合是个好主意,更好的方法是按照Quuxplusone的建议将Class封装在C++类中。

但是,要回答您的问题,我能想到的“最干净的”(但仍然是丑陋的方法)是在创建对象之后,将原始指针传递给带有自定义删除器的智能指针。

代码语言:javascript
复制
struct FMOD_SYSTEM_Deleter {    
    void operator()(FMOD_SYSTEM* sys) {
         if (sys !=  nullptr) {
             FMOD_System_Release(sys);
         }
    }
}

FMOD_SYSTEM* tsys = nullptr;
result = FMOD_System_Create(&tsys);
std::unique_ptr<FMOD_SYSTEM,FMOD_SYSTEM_Deleter> system(tsys);
票数 3
EN

Stack Overflow用户

发布于 2014-12-28 23:44:36

简单的答案是: C++智能指针用于使用newdelete创建的自分配对象。它们不是为指向对象的指针而构建的,这些对象是由第三方C样式API函数内部创建的,需要由另一个C样式API函数发布。在您的情况下,您必须调用System::release而不是delete,因此使用智能指针可能会造成很大的问题。

你有三种可能性:

  1. 只需保持C风格,并照顾调用释放你自己。(我更喜欢这个)
  2. 编写您自己的C++包装类,如Quuxplusone建议的
  3. 使用自定义的“分配器”和“删除器”修改C++智能指针(这是复杂的,理论上的,不建议使用)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27680981

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档