When using the fftw3 fast fourier transform (FFT) library, a plan variable is declared and initialised, it is then used to perform some FFTs and subsequently destroyed when the memory is to be freed:
#include <fftw3.h>
// Declare plan
fftw_plan myPlan;
// Initialise plan
myPlan = fftw_plan_dft_r2c(3, m, f, reinterpret_cast<fftw_complex*>(fk.get()), FFTW_PATIENT);
// Perform an FFT
fftw_execute(myPlan);
// Free the memory associated with the plan
fftw_destroy_plan(myPlan);
In the above: m, f and fk.get() are raw pointers to arrays and the code runs perfectly well.
However, I've been attempting to set up this process using a smart pointer that will automatically free the memory when the plan goes out of scope. This is what I have come up with:
std::unique_ptr<fftw_plan, decltype(&fftw_destroy_plan)> myPlan(
fftw_plan_dft_r2c(3, m, f, reinterpret_cast<fftw_complex*>(fk.get()), FFTW_PATIENT),
fftw_destroy_plan
);
Unfortunately, I get the following compiler error:
no instance of constructor "std::unique_ptr<_Tp, _Dp>::unique_ptr [with _Tp=fftw_plan, _Dp=void (*)(fftw_plan p)]" matches the argument listC/C++(289)
strFunc.cc(26, 9): argument types are: (fftw_plan, void (fftw_plan p))
I can see that the types of the second arguments don't match, but dereferencing doesn't seem to fix the issue (and I don't see why it would).
If anyone has some insights as to how to progress, I would greatly appreciate it!
Thanks!
2 Answers 2
If I understand the documentation correctly, then fftw_plan is an opaque pointer type.
In that case you can do:
struct deleter {
// this alias is important for unique_ptr
using pointer = fftw_plan;
void operator()(pointer plan) const { fftw_destroy_plan(plan); }
};
std::unique_ptr<void, deleter> myPlan(fftw_plan_dft_r2c(/*...*/));
The important part here is that pointer must be a type that behaves like a pointer with respect to nullptr. That means there is an empty state that compares equal to nullptr (while others don't) and can be assigned/constructed from nullptr. unique_ptr needs this state for an empty or moved-from instance.
1 Comment
A bit to add to this answer: fftw_plan is actually a pointer to fftw_plan_s. Here's a typedef from api:
typedef struct X(plan_s) *X(plan);
So you could keep the deleter and write something like
struct Deleter {
using pointer = fftw_plan;
void operator()(pointer p) { fftw_destroy_plan(p); }
};
std::unique_ptr<fftw_plan_s, Deleter> plan(/*create plan*/);
fftw_execute(plan.get());
or even write it without the deleter at all using pointer to function
std::unique_ptr<fftw_plan_s, decltype(&fftw_destroy_plan)>plan(/*create plan*/, fftw_destroy_plan);
fftw_execute(plan.get());
P.S. I'd better comment on the previous answer, but I don't have enough score to do so..
Edit: added option without deleter struct
1 Comment
unique_ptr variables are twice as large as with struct Deleter, because there must be room for the function pointer. Additionally, such unique_ptrs are (unnecessarily?) generic, because they could in theory hold a different function pointer---the spot in the variable is, well, variable, after all.
std::unique_ptr<T>wants to holdT*, notT; and passT*to the deleter. It's difficult to make it work with a resource that's not a pointer.fftw_plan? Is it known to be a nullable type that supports assignment/comparison withnullptr?std::unique_ptr<T, Deleter>wants to holdDeleter::pointerif that is defined; otherwiseT*. So to make this work, you would need a custom deleter that would, among other things, have a member typedefusing pointer = fftw_plan;. Just a plain function pointer won't cut it as a deleter.