Question

I have the following code below,

std::complex<double>** x;
x = calloc(10,sizeof(complex <double> *));

This code failed to compile with the following error message.

error: invalid conversion from 'void*' to 'std::complex<double>*' [-fpermissive]

How can I successfully compile? Why does this code fail to compile?

Was it helpful?

Solution 2

In C++, void * doesn't automatically cast to other pointers (unlike in C). So if you use malloc and the family in C++, you need to cast the result yourself.

However, you should note that malloc doesn't understand C++'s constructors. So if you want to allocate a C++ object (not a C struct for example, or more precisely a POD), you should use new (and delete/delete[] correspondingly) which correctly takes care of constructors and destructors.

Alternatively, you can use one of the many structures provided by the standard library, such as std::vector.

OTHER TIPS

You're trying to write C++ as if it were C, which allows dangerous implicit conversions like this.

To allocate a dynamic array of size 10, use

std::vector<std::complex<double>> numbers(10);

and, if you really want a pointer to the first element

x = numbers.data();

The problems.

This code from the question, …

    x = calloc(10,sizeof(complex <double> *));

is ungood for two reasons:

  • unlike C, C++ does not have an implicit conversion from void*, and

  • creating a jagged array by means of C++ new is bad enough, doing it with the C level allocation functions is general an abomination (except where required by some function that one needs to call).

The first bullet point is why it fails to compile in C++.


What to do.

A purely technical fix is to use a cast, and then preferably a C++ named cast such as static_cast or reinterpret_cast. Both work fine in practice for conversion from void*. However, in my opinion reinterpret_cast expresses the conceptual operation more correctly, so I’d choose that – if I chose to cast.

A slightly better solution is to use C++ new instead of C calloc. With new you have to add an empty parenthesis at the end to to get the guaranteed zero-initialization of calloc. But the main problem is still that it's every low level and difficult (much work) to get right.

A much better general solution is to use a C++ container class.

The standard library offers std::vector, with which the jagged array can be constructed like this:

typedef complex<double> Complex;
typedef vector<Complex> ComplexVec;
typedef vector<ComplexVec> ComplexVec2D;

ComplexVec2D x( 10 );

Then each ComplexVec can just be resized, since std::vector is a dynamically sized array.


What to do if you really want a MATRIX.

If you really want a matrix, i.e. an array of arrays of equal length, then instead of a jagged array consider a C++ class which just provides 2D indexing into a single vector.

In C++03-style it can go like this (off the cuff code):

typedef complex<double> Complex;

class ComplexMatric
{
private:
    vector<Complex> items_;
    int             width_;

public:
    Complex& operator()( int x, int y )
    { return items_[y*width_ + x]; }

    Complex const& operator()( int x, int y ) const
    { return items_[y*width_ + x]; }

    ComplexMatrix( int w, int h )
        : items_( w*h )
        , width_( w )
    {}
};

And you'd use it like this:

ComplexMatrix x( 10, some_height );

This includes doing proper allocation and deallocation, and even supporting copying by assignment.

Disclaimer: code untouched by compiler's hands.

Instead of using calloc, try using new[] operator instead. This is the C++ way to dynamically create an array.

x = new complex<double>[10];

The new[] returns a pointer to whatever type followed the operator, in this case it is a pointer with type complex<double> which points to an array of complex<double> with 10 elements inside.

Be aware, though, you have to use delete[] operator to deallocate the memory (not free()). Otherwise no one know what's going to happen :-).

delete[] x;

Assuming your x is of type std::complex<double>*, you get this error because calloc returns a void pointer. Without -fpermissive implicit casts are not allowed. So, you'll have to cast between void* and std::complex<double>*. However, in C++ it is recommended to use new instead of malloc or calloc, and personally I'd recommend you to use std::vector.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top