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

标签 c pointers c++11 smart-pointers

虽然这应该是一个微不足道的问题,但到目前为止我还找不到答案。在 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 - 使用 C++11 智能指针作为 C 函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27680981/

相关文章:

android - 树莓派 : Create a RPi server which can be accessed from another device

c - C中的单链表输出不正确

c++ - std::wcout 奇怪的错误:std::wstring 的截断输出

python - 在 C 中解包 (r,g,b) 原始像素缓冲区

c++ - 我可以向数组指针添加元素吗?

c++ - 堆内存的范围

c++ - 具有指针 C 成员的类 C 的析构函数

pointers - 通用访问类型 Ada

c++ - 为什么移动语义与动态内存分配中的浅拷贝具有相同的行为?

c++ - 一段代码不能被intel编译器编译但是clang会编译它