C++智能指针与更改指针值一起使用
C++ use Smart Pointers with changing pointer values
考虑一个C库,它定义了用于创建,销毁和使用自定义结构的函数
struct Foo;
void foo_action(Foo*);
Foo* foo_create();
void foo_free(Foo*);
目前,我在C++项目中使用了该库,如下所示
Foo* myfoo = foo_create();
foo_action(myfoo);
foo_free(myfoo);
我理解为什么智能指针很重要,并希望迁移我的代码以使用它们。这就是代码现在的样子。
#include <memory>
#include <functional>
typedef std::unique_ptr<Foo, std::function<void(Foo*)>> FooPtr;
// ...
FooPtr myfoo2(foo_create(), foo_free);
foo_action(myfoo2.get());
它似乎有效,但myfoo2.get()
调用似乎很笨拙。我是否按预期使用它?
库的另一部分创建并使用某种列表结构。该 api 看起来像
struct Bar;
Bar* bar_append(Bar*, int);
void bar_free_recursive(Bar*);
并用作
// using NULL as current Bar* creates the initial structure
Bar* bar = bar_append(NULL, 1);
// each invocation leads to another 'head' structure
bar = bar_append(bar, 42);
bar = bar_append(bar, 123);
由于指针(指向的地址)随着每次bar_append
调用而变化,我将如何在此处引入智能指针,以便在释放指针实例时对当前指针值调用bar_free_recursive
?
但是myfoo2.get()调用似乎很笨拙。我是否按预期使用它?
它不是黑客,您可以按预期使用它。
我会更进一步,将整体包装在一个类中:
struct Foo;
void foo_action(Foo*);
Foo* foo_create();
void foo_free(Foo*);
class FooWrapper
{
public:
FooWrapper() : mFoo(foo_create()) {}
void action() { foo_action(mFoo.get()); }
private:
struct FooDeleter
{
void operator()(Foo* foo) const { foo_free(foo); }
};
std::unique_ptr<Foo, FooDeleter> mFoo;
};
以同样的方式:
struct Bar;
Bar* bar_append(Bar*, int);
void bar_free_recursive(Bar*);
class BarWrapper
{
public:
explicit BarWrapper(int n) : mBar(bar_append(nullptr, n)) {}
void append(int n) { mBar.reset(bar_append(mBar.release(), n)); }
private:
struct BarDeleter
{
void operator()(Bar* bar) const { bar_free_recursive(bar); }
};
std::unique_ptr<Bar, BarDeleter> mBar;
};
<</div>
div class="answers"> 必须编写.get()
是使用智能指针的不幸后果,但我认为如果您想传递给接受非拥有的、可为空的指针的函数,这是最佳实践。
但是,在实践中,我经常发现您不需要它为空,并且可以接受引用而不是原始指针。然后语法就不那么"黑客"了:
void foo_action(Foo&); // accept a reference instead of a raw-pointer
struct FooDeleter {
void operator()(Foo* foo) const { foo_free(foo); }
};
using FooPtr = std::unique_ptr<Foo, FooDeleter>;
FooPtr make_foo() {
return FooPtr(foo_create());
}
int main() {
auto foo = make_foo();
// ...
if (foo) { // check for null
foo_action(*foo); // dereference smart-pointer
}
}
bar_append
应使用unique_ptr
,前提是您使用std::move
:
struct BarDeleter {
void operator()(Bar* bar) const { bar_free_recursive(bar); }
};
using BarPtr = std::unique_ptr<Bar, BarDeleter>;
BarPtr bar_append(BarPtr bar, int value) {
return BarPtr(bar_append(bar.release(), value));
}
int main() {
BarPtr bar;
bar = bar_append(std::move(bar), 42);
bar = bar_append(std::move(bar), 123);
}
我会说myfoo2.get()
笨拙,而不是笨拙。
我会亲自创建一个基于模板的包装器obj_ptr
(你选择一个更相关的名称),并为每种类型的对象使用特征来C++的方式对你的要求进行建模。然后,包装器可以消除访问基础对象的笨拙。
template <typename T, typename Traits>
class obj_ptr final
{
std::unique_ptr<Foo, void(*)(T*)> ptr_{ Traits::create(), Traits::free };
public:
operator T*() { return ptr_.get(); }
operator const T*() const { return ptr_.get(); }
T* operator->() { return ptr_.get(); }
const T* operator->() const { return ptr_.get(); }
};
class foo_traits
{
public:
static Foo* create() { return foo_create(); }
static void free(Foo* foo) { foo_free(foo); }
};
int main()
{
using FooPtr2 = obj_ptr<Foo, foo_traits>;
FooPtr2 myfoo2;
foo_action(myfoo2);
return EXIT_SUCCESS;
}
相关文章:
- 在将 new 与指针一起使用时,创建数组的指定长度
- 为什么我们将 [ ] 与指向数组的指针一起使用?
- 如何将数组与指针一起使用?
- 如何将 string.erase() 与指针一起使用?
- __unaligned说明符何时与指针一起使用?
- 为什么在将多态行为与指向接口的指针一起使用时没有调用析构函数?
- 自动关键字与智能指针一起
- shared_ptr ::重置仅与原始指针一起使用
- 为什么动态演员只能与参考和指针一起使用
- 是否可以将SDL2与智能指针一起使用
- 如何将此指针与指向成员函数的指针一起使用
- 将shared_ptr与指向指针的指针一起使用时出现编译器错误
- 将 std::sort 与指向整数变量的指针一起使用会产生意外的输出
- QtConcurrent::run 是否可以与指向对象的智能指针一起使用
- 重新分配指针后,将类功能与指针一起使用
- 将共享指针的别名构造函数与空共享指针一起使用C++
- 如何将转换构造函数与指针一起使用?
- 如何 RAII 与指针一起使用
- Vtables是否仅与指向基类的指针一起使用
- 将 decltype 与虚拟成员函数指针一起使用