4

How do you allocate a 2D array of pointers to objects?

Currently I have:

file.h

extern ClassName **c;

file.cpp

ClassName **c;
int main(){
    // some stuff
    c = new ClassName*[sizex];
    for(int i = 0; i < sizex; ++i){
        c[i] = new ClassName[sizey];
    }

    for(int i = 0; i < sizex; ++i){
        for(int j = 0; j < sizey; ++j){
            c[i][j] = new ClassName();
        }
    }

Which fails to compile with error's stating that there is no match for operator= using ClassName and ClassName*, which looking at the error makes sense. But if I were to change the assignment of c[i][j] to

ClassName cn();
c[i][j] = cn;

It gives a plethora of other errors. The array's size cannot be known until runtime (read from stdin) and it must also be extern. What is the proper way to declare an array in this case?

5
  • 2
    If array size can't be known until runtime, you are way better off with std::vector<Classname**>. You're actually almost always better off with std::vector Commented Dec 11, 2014 at 19:10
  • While I totally second your comment, it does not actually answer the question. Commented Dec 11, 2014 at 19:11
  • Please show the exact error message. Commented Dec 11, 2014 at 19:11
  • Don't. Why would you? Commented Dec 11, 2014 at 19:13
  • @kiss-o-matic It would probably be std::vector<ClassName*> as the double-pointer is only necessary in a C-style array of arrays. Commented Dec 11, 2014 at 19:27

5 Answers 5

4

You have to declare the pointer like

extern ClassName ***c;

The allocation will look like

c = new ClassName**[sizex];
for(int i = 0; i < sizex; ++i){
    c[i] = new ClassName*[sizey];

    for(int j = 0; j < sizey; ++j){
        c[i][j] = new ClassName();
    }
}

You could define the 2D array correctly yourself if you would declare the array of some abstract type T. Then all you need is to change T to ClassName *

As for this declaration

ClassName cn();

then it declares a function that has return type ClassName and has no parameters.

Sign up to request clarification or add additional context in comments.

8 Comments

@LightnessRacesinOrbit He's answering the question. Sure, it could do with a paragraph or two about why this is not a good way to do this, but answering the question comes first.
@Lightness Races in Orbit I am showing correct declarations instead of wrong declarations.
@Joseph Answering the question comes second, after a HUGE warning that none of this should ever make its way into production code. Ever. Just because it compiles doesn't mean it's advisable in any way, shape or form.
@LightnessRacesinOrbit This is a question and answer site. Not a professional advice site.
@Daniel There's vomit on his sweater already, mom's spaghetti... </eminem>, also Lightness is right, this should encourage better programming as well as answer questions.
|
4
ClassName *p1;

p1 can point to one ClassName or an array of ClassNames.

ClassName **p2;

p2 can point to one ClassName* or an array of ClassName*s.

*p2 can point to one ClassName or an array of ClassNames.

When you use:

   c[i] = new ClassName[sizey];

you are allocating memory so that c[i][j] can hold a ClassName but not a ClassName*.

If c[i][j] = ClassName(); is failing, and you want to use c[i][j] = new ClassName();, then c has to be declared as:

 ClassName*** c;

However, in stead of doing that, I strongly suggest use of std::vector and a smart pointer.

 std::vector<std::vector<std::unique_ptr<ClassName>>> c;

1 Comment

Add 1 for vector suggestion, wish i could +2 for smart pointer.
4

The previous posters have answered correctly about using the tripple pointer, but for your sanity, and the clarity of your code, you can make use of a couple of simple typedefs:

typedef ClassName* Row;
typedef Row* Matrix;

Matrix *M;  //equivalent to : ClassName ***M, 
            //check by substiting Matrix with Row* and Row with ClassName*
int main()
{
   M = new Matrix[numRows];

   for(int row = 0; row < numRows; ++row)
   {
        M[row] = new Row[numCols];

        for(int col = 0; col < numCols; ++j)
        {
            M[row][col] = new ClassName();
        }
    }
}

this communicates your intent better, and is easier to reason about.

Comments

0

You need change your type to: ClassName ***c; as Vlad from Moscow mentioned.

ClassName **c;
int main(){
    // some stuff
    c = new ClassName**[sizex];
    for(int i = 0; i < sizex; ++i){
        c[i] = new ClassName*[sizey]
    }

    for(int i = 0; i < sizex; ++i){
        for(int j = 0; j < sizey; ++j){
            c[i][j] = new ClassName();
        }
    }

Your usage has to change too:

ClassName cn;
c[i][j] = new ClassName( cn );  // <-- this copy constructor would cause a memory leak (old pointer not deleted)
*(c[i][j]) = cn;                // <-- this would use the assignment operator.  May be weak performance.
ClassName & cn = *(c[i][]);     // <-- Allows you to work directly on the cell.

2 Comments

Although I can agree that triple pointer is an inferior approach, it is not prohibited nor incorrect. The poor guy is obviously trying to learn about new[] and make a double dimension array of pointers. Personally, I would use a single array or vector of unique_ptr encapsulated within a class with an accessor taking an (x,y) parameter to dereference the pointer, but that was not what was asked. Why don't you give him the solution instead of criticizing everyone else's attempt to help him along his code?
Peer review is a crucial part of any scientific discourse. I suggest getting used to receiving it. :)
0

ClassName **c is a 2D array ie c[n][m] of ClassName objects.

You have attempted to assign c[n][m] of type ClassName as new ClassName() of type ClassName*

for(int i = 0; i < sizex; ++i){
    for(int j = 0; j < sizey; ++j){
        c[i][j] = *(new ClassName);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.