Consider a C library that defines functions for creating, destroying and working with a custom structure
struct Foo; void foo_action(Foo*); Foo* foo_create(); void foo_free(Foo*);
Currently, I used the library in my C++ project as follows
Foo* myfoo = foo_create(); foo_action(myfoo); foo_free(myfoo);
I understand why smart pointers are important and want to migrate my code to use them. That's how the code looks now.
#include <memory> #include <functional> typedef std::unique_ptr<Foo, std::function<void(Foo*)>> FooPtr; // ... FooPtr myfoo2(foo_create(), foo_free); foo_action(myfoo2.get());
It seems to work, but the myfoo2.get()
invocation seems hacky. Am I using it as intended?
There's another part of the library which creates and works with some kind of list structure. The api looks like
struct Bar; Bar* bar_append(Bar*, int); void bar_free_recursive(Bar*);
and is used as
// 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);
As the pointer (the address pointed to) changes with each bar_append
invocation, how would I introduce smart pointers here, so that bar_free_recursive
is invoked on the current pointer value when the pointer instance is freed?
Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.
Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.
Single most important reason as to why auto_ptr was deprecated in favor of smart-pointer is assignment-semantics If it wasn't for that reason, they would have added all the new goodies of move semantics to the auto_ptr instead of deprecating it.
You cannot assign the value of a pointer directly to a shared_ptr object. You may either use make_shared or member reset instead.
but the myfoo2.get() invocation seems hacky. Am I using it as intended?
It is not hacky, you use it as intended.
I would go one step further and wrap the whole in a class:
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; };
In the same way:
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; };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With