Share via


Variable sized arrays in C++ classes?

Question

Wednesday, July 9, 2014 12:56 PM

The following code compiles in code::blocks (using the gcc compiler) but not in VS-C++. So I conclude that, variable sized arrays in classes are not allowed in VS-C++. Am I right or is there a way to get around this issue?

btw, gcc compiles but warns me like:

"warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]"

...

int MaxDim;

class CMatrix
{
public:
    int n = MaxDim;
    int nSqr = n * n;
    double *a = new double [nSqr];
    double *b = new double [n];
    CMatrix (string s)
    {
        ...
    }
    ~CMatrix ()
    {
        ...
    }
};

...

void main ()
{
    ...
    FileInput >> MaxDim;
    ...
    CMatrix* a;
    a = new CMatrix ("Matrix.txt");
    ...
    delete (a);
}

All replies (9)

Wednesday, July 9, 2014 3:13 PM ✅Answered | 1 vote

I conclude that, variable sized arrays in classes are not allowed in VS-C++.

That's an exaggeration. You can do the allocations in the constructor:

#include "stdafx.h"
#include <string>

using namespace std;

int MaxDim;

class CMatrix
{
public:
//    int n = MaxDim;
//    int nSqr = n * n;
    int n; // ***
    int nSqr; // ***
//    double *a = new double [nSqr];
//    double *b = new double [n];
    double *a; // ***
    double *b; // ***
    CMatrix (string s)
    {
        n = MaxDim; // ***
        nSqr = n * n; // ***
        a = new double [nSqr]; // ***
        b = new double [n]; // ***

//        ...
    }
    ~CMatrix ()
    {
    delete[] a; // ***
    delete[] b; // ***
//        ...
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    CMatrix cm("testit");
    
    return 0;
}

Note that relying on the existence of a global variable such as MaxDim in this example and
your posted code is definitely a bad idea. Better to pass it as an argument to the constructor.

 - Wayne


Wednesday, July 9, 2014 3:27 PM ✅Answered | 1 vote

Note that relying on the existence of a global variable such as MaxDim in this example and

your posted code is definitely a bad idea. Better to pass it as an argument to the constructor.

As in this example:
 

class CMatrix
{
public:
    int n;
    int nSqr;
    double *a;
    double *b;
    CMatrix (string s, int MaxDim) : n(MaxDim)  // ***
    {
        nSqr = n * n;
        a = new double [nSqr];
        b = new double [n];

//        ...
    }
    
int _tmain(int argc, _TCHAR* argv[])
{
    int MaxDim = 10;
    CMatrix cm("testit", MaxDim);
    return 0;
}

- Wayne


Wednesday, July 9, 2014 9:44 PM ✅Answered

This is what I did and it's working perfect! Thanks again WayneAKing. You made my day.

edit: "delete (a);" converted to "delete [] a;" as Wayne suggested.

#include <iostream>
#include <fstream>
#include <string>

class CMatrix
{
public:
    int n;
    double *a, *u, *i, *b, *x;
    CMatrix (string FileName, int MatrixDim)
    {
        n = MatrixDim;
        a = new double [n * n];
        u = new double [n * n];
        i = new double [n * n];
        b = new double [n];
        x = new double [n];
        ...
        ...
        ...
    }
    ~CMatrix ()
    {
        MatrixFreeMem ();
    }
    void MatrixFreeMem ()
    {
        delete [] a;
        delete [] u;
        delete [] i;
        delete [] b;
        delete [] x;
    }
    ...
    ...
    ...
};

...
...
...

void main ()
{
    ...
    ...
    ...
    CMatrix *A;
    A = new CMatrix (gAppPath + gDataFileName, MaxDim); // max dim read previously from another file
    A -> MatrixSolve ();
    delete A;
}

Wednesday, July 9, 2014 10:11 PM ✅Answered | 1 vote

    CMatrix (string FileName, int MatrixDim)
    {
        n = MatrixDim;
        a = new double [n * n];
        u = new double [n * n];
        i = new double [n * n];
        b = new double [n];
        x = new double [n];
        ...
        ...
        ...
    }
    ~CMatrix ()
    {
        MatrixFreeMem ();
    }
    void MatrixFreeMem ()
    {
        delete (a);
        delete (u);
        delete (i);
        delete (b);
        delete (x);
    }

Your delete statements are of the wrong form. They should be:

delete[] a;
delete[] u;
delete[] i;
delete[] b;
delete[] x;

Use delete[] when you use new[] and use delete when you use new.

This is critical when the objects are classes, as using new[] calls the constructors for
each object in the array and delete[] calls the destructors for each object in the array.
Using delete instead of delete[] will cause the dtors to be skipped (with the possible
exception of the first one) - and the actual behaviour will be "undefined".

Note that parentheses are not needed:

char *c = new char[10];
...
delete[] c;

MyClass *mc = new MyClass;
...
delete MyClass;

  • Wayne

Wednesday, July 9, 2014 2:45 PM | 1 vote

The following code compiles in code::blocks (using the gcc compiler) but not in VS-C++. So I conclude that, variable sized arrays in classes are not allowed in VS-C++.

gcc compiles but warns me like:

"warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]"

It would help of you stated which *version* of VC++/VS you're using. According to this table:

Support For C++11 Features (Modern C++)
http://msdn.microsoft.com/en-us/library/hh567368.aspx

"Non-static data member initializers" is an available feature in VS/VC++ 2013 but not in
earlier versions.

  • Wayne

Wednesday, July 9, 2014 3:42 PM

On 09/07/2014 14:56, merkez3110 wrote:

The following code compiles in code::blocks (using the gcc compiler) but not in VS-C++. So I conclude that, variable sized arrays in classes are not allowed in VS-C++. Am I right or is there a way to get around this issue?

btw, gcc compiles but warns me like:

"warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]"

The problem is not variable sized arrays in classes, the problem is non-static data member initializer feature, that is a C++11 feature that might not be implemented in the Visual C++ compiler that you are using.

WayneAKing already posted a link to a table with C++11 features implemented in Visual C++, and also offered an alternative solution if non-static data member initializer feature is not available.

I'd just like to add that using RAII-based STL containers like std::vector is much better than using those raw C like array, which tend to produce code that can leak memory, is exception unsafe, and is also more complex.

Consider just using std::vector<double> instead of your raw C-like heap allocated double arrays.

Giovanni


Wednesday, July 9, 2014 5:21 PM

Thanks for the reply. I'm using VS-2012 and now I see that why I can't compile.


Wednesday, July 9, 2014 10:34 PM

I will take into account: convert "delete (a)" to "delete [] a".


Friday, July 11, 2014 5:42 PM

On 10/07/2014 00:11, WayneAKing wrote:

         CMatrix (string FileName, int MatrixDim)
         {
                 n = MatrixDim;
                 a = new double [n * n];
                 u = new double [n * n];
                 i = new double [n * n];
                 b = new double [n];
                 x = new double [n];
                 ...
                 ...
                 ...
         }
         ~CMatrix ()
         {
                 MatrixFreeMem ();
         }
         void MatrixFreeMem ()
         {
                 delete (a);
                 delete (u);
                 delete (i);
                 delete (b);
                 delete (x);
         }

Your delete statements are of the wrong form. They should be:
delete[] a; delete[] u; delete[] i; delete[] b; delete[] x;
Use delete[] when you use new[] and use delete when you use new.

Just use std::vector, and you don't have to remember to delete/delete[] anything. In modern C++ code, convenient RAII building blocks like std::vector should be used, instead of those old C style raw new/new[] and delete/delete[] (unless there is a particular need to do that). Giovanni