1

The current C++ compilers fail to find a suitable overload for std::shared_ptr when using a C-array as a type.

I can make it a real std::array object and that works, but the library I'm linking against (fftw3) has already created the typedef and uses it in all of it's C-API calls.

#include <memory>
typedef double fftw_complex[2];

int main(int argc, char* argv[])
{
        fftw_complex bob; //works fine
        bob[0]=2; bob[1]=-1; //works fine
        std::shared_ptr<fftw_complex> handle; //works fine
        std::shared_ptr<double> other(new double[35]); //works fine
        handle = std::shared_ptr<fftw_complex>(new fftw_complex[35]);//can't find constructor
        return 0;
}

Up until a few months ago this worked fine with all compilers. With the update to gcc to version 7.3, 8.2, and 9 I now get an error when trying to compile the non-void constructor. I suspect it is because of the "improvements" to std::shared_ptr to automatically handle when T is an array type.

I get the error

complex_shared.cpp:12:61: error: no matching function for call to 'std::shared_ptr<double [2]>::shared_ptr(double (*)[2])'
   12 |  handle = std::shared_ptr<fftw_complex>(new fftw_complex[35]);

and the somewhat difficult to parse error message

 note: candidate: 'template<class _Yp, class> std::shared_ptr<_Tp>::shared_ptr(_Yp*)'
  139 |  shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
      |  ^~~~~~~~~~
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:139:2: note:   template argument deduction/substitution failed:
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h: In substitution of 'template<class _Tp> template<class ... _Args> using _Constructible = typename std::enable_if<std::is_constructible<std::__shared_ptr<_Tp>, _Args ...>::value>::type [with _Args = {double (*)[2]}; _Tp = double [2]]':
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:137:30:   required from here
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:106:8: error: no type named 'type' in 'struct std::enable_if<false, void>'
  106 |  using _Constructible = typename enable_if<
Meta.x.gdb
  • 173
  • 1
  • 6
  • 1
    using `shared_ptr` for an array of double is not a good idea. See here : https://stackoverflow.com/questions/13061979/shared-ptr-to-an-array-should-it-be-used – Louen Sep 09 '19 at 22:36
  • I'm just using it as an example of what the compiler will compile, and not compile. – Meta.x.gdb Sep 09 '19 at 22:44
  • Have you tried declaring it as a `>` if you're in C++ 17 ? – Louen Sep 09 '19 at 22:54

1 Answers1

1

it seems you have to let std::shared_ptr know that this is not a normal pointer but is indeed a pointer to an array

#include <memory>
typedef double fftw_complex[2];

int main(int argc, char* argv[])
{
    fftw_complex bob;
    bob[0]=2; bob[1]=-1;
    std::shared_ptr<fftw_complex[]> handle;
    std::shared_ptr<double> other(new double[35],[](double* p){ delete[] p;});
    std::shared_ptr<double[]> nother(new double[35]); //std::shared_ptr will call delete[]
    handle = std::shared_ptr<fftw_complex[]>(new fftw_complex[35], [](fftw_complex* p){ /* special delete logic*/;});
    return 0;
}

to be clear, I have to use the fftw_malloc and fftw_free functions for this memory, so I will be providing my own deleter for the fftw_complex type. delete[] is incorrect for these library-provided data elements.

Meta.x.gdb
  • 173
  • 1
  • 6