G++ gives cryptic error messages, some pointer issue - c++

I'm new to C++ and struggling trying to make multi-file programs work. I had a Graph library functioning in C, and I am running into trouble converting it to C++. My biggest problem from g++ is this error message,
error: no match for âoperator=â in â*(((Graph*)this)->Graph::adj +
((long unsigned int)(((long unsigned int)i) * 32ul))) = (operator
new(32u), (<statement>, ((List*)<anonymous>)))â
Here is the section of my Graph.cpp code it is complaining about:
Graph::Graph(int n){
order = n;
size = 0;
source = NIL;
color = static_cast<char*>(calloc(n + 1, sizeof(char)));
distance = static_cast<int*>(calloc(n + 1, sizeof(int)));
parent = static_cast<int*>(calloc(n + 1, sizeof(int)));
adj = static_cast<List*>(calloc(n + 1, sizeof(List*)));
discover = static_cast<int*>(calloc(n + 1, sizeof(int)));
finish = static_cast<int*>(calloc(n + 1, sizeof(int)));
int i;
for(i = 0; i <= n; i++){
color[i] = 'w';
distance[i] = INF;
parent[i] = NIL;
adj[i] = new List();
}
}
As you can see I'm using a bit of a hybrid between C and C++, but a pure C++ implementation doesn't work either. Further down in my file, I constantly get the error " error: base operand of â->â has non-pointer type âListâ", and I think it all comes from how I'm declaring. I've looked around on here and have found other people complaining of this error, but I haven't seen it help with assigning to an array. Help would be awesome, because except for this I know it all works.

You have declared Graph::adj to be of type List* (adj[i] is the same as doing *(adj+i)), and dereferencing a pointer to type T will yield a value of type T, ie. the type of adj[i] is List.
If you really want to do what you are trying to do declare Graph::adj as List**, that way it will be a pointer to a bunch of pointers to List, not a pointer to a bunch of Lists.
I don't understand, what the heck are you trying to say?
You are trying to assign a List* (returned by new List) to a variable of type List.
struct List {
// ...
};
List ** adj = static_cast<List**> (
std::calloc (10, sizeof (List*))
);
/* error
List * adj = static_cast<List*> (
std::calloc (10, sizeof (List*))
);
*/
adj[0] = new List;
Okay, I get you.. but there must be a better way to solve this issue?
There sure is, use what c++ provides you with and ditch your old C habits.
List * adj = new List [10]; // create an array of 10 List
adj[i].member_of_List ...; // example
delete [] adj; // free up allocated memory when you are done

Line
adj = static_cast<List*>(calloc(n + 1, sizeof(List*)));
suggests that adj is an array of List objects, while line
adj[i] = new List();
suggests that it is an array of pointers. You should check the definition of adj. By the way, the error refers to the latter line.
Types
I'll elaborate a little more on the theoretical aspects of the problem, which revolves around the C++ type system.
In C++ every expression has a type, known at compile time. The type of any expression of the form
static_cast<List*>(...)
is
List *
That is, provided that the type of the expression in parenthesis can be statically casted to List *, the compiler will not complain and the final type of the expression will be List *. Function calloc returns void * which can be casted to any other pointer; in fact, pointer casts are often only a way to tell the compiler yes, I know what I'm doing, shut up. On most platforms all pointer types have the same bit representation, although the standard does not mandate such a thing, hence in principle no machine code needs to be generated to implement such cast.
The type of an expression such as
new List()
or
new List[10]
is
List *
and an instruction that includes such instructions allocates enough space for a List object or for 10 list objects and returns a pointer to such space.
You would probably be better off if you replace the line
adj = static_cast<List*>(calloc(n + 1, sizeof(List*)));
with
adj = new List[n + 1];
If adj is a pointer type, the type of an expression such as
adj[i]
or
*(adj + i)
or even simply
*adj
is the pointer type minus one of its asterisks; that is, if the type of adj is
List *
the type of adj[i] is
List
That is the reason why you get the error at the line adj[i] = new List(); it doesn't make sense to assign
List *
to
List
The good news, is that if you allocate adj with the new operator, you probably don't need to create with new every single element; when you allocate an array with new, all its elements are created and their constructor is automatically invoked by the compiler.
Possible solution
Since the rest of your program is aparently correct, you may simply erase the line
adj[i] = new List()
and everything should work fine. However as john noted, your intent is not very clear; you really need to tell us if you want adj to be an array of objects
List *adj;
or an array of pointers
List **adj;
Advanced topic
The practical difference between using the C way
adj = static_cast<List*>(calloc(n + 1, sizeof(List*)));
or the C++ way
adj = new List[n + 1];
Is that the constructor of each of the allocated List objects doesn't get called with the former method. There are a few applications of pointers in which you may want this to be the case, but in general you shouldn't mix C and C++.

A hybrid mix of C and C++ is actually going to be harder than pure C++.
In this case the problem seems to be that you have
class Graph
{
...
List* adj;
...
};
so
adj[i] = new List();
is wrong because adj[i] is of type List and new List() is of type List*.
The fix for this is to use placement new.
#include <new>
new (adj + i) List();
This will construct a List at address &adj[i] which is what you are trying to achieve I think.
But this is advanced C++ and is only necessary because you are trying to write a mix of C and C++. I would ditch the C part as soon as possible.
EDIT
OK as refp points out (and I missed) you have
adj = static_cast<List*>(calloc(n + 1, sizeof(List*)));
My answer is only correct if that is a mistake and you intended
adj = static_cast<List*>(calloc(n + 1, sizeof(List)));

Related

initialize an int[][] with new()

I am a c++ newbie. While learning I came across this.
if I have a pointer like this
int (*a)[2][3]
cdecl.org describe this as declare a as pointer to array 2 of array 3 of int:
When I try
int x[2][3];
a = &x;
this works.
My question is how I can initialize a when using with new() say something like
a = new int [] [];
I tried some combinations but doesn't get it quite right.
Any help will be appreciated.
You will have to do it in two steps - first allocate an array of pointers to pointers(dynamically allocated arrays) and then, allocate each of them in turn. Overall I believe a better option is simply to use std::vector - that is the preferred C++ way of doing this kind of things.
Still here is an example on how to achieve what you want:
int a**;
a = new int*[2];
for (int i =0; i< 2;++i){
a[i] = new int[3]
}
... use them ...
// Don't forget to free the memory!
for (int i = 0; i< 2; ++i) {
delete [] a[i];
}
delete [] a;
EDIT: and as requested by Default - the vector version:
std::vector<std::vector<int> > a(2, std::vector<int>(3,0));
// Use a and C++ will take care to free the memory.
It's probably not the answer you're looking for, but what you
need is a new expression whose return type is (*)[2][3] This
is fairly simple to do; that's the return type of new int
[n][2][3], for example. Do this, and a will point to the
first element of an array of [2] of array of [3] int. A three
dimensional array, in sum.
The problem is that new doesn't return a pointer to the top
level array type; it returns a pointer to the first element of
the array. So if you do new int[2][3], the expression
allocates an array of 2 array of 3 int, but it returns
a pointer to an array of 3 int (int (*a)[3]), because in C++,
arrays are broken (for reasons of C compatibility). And there's
no way of forcing it to do otherwise. So if you want it to
return a pointer to a two dimensional array, you have to
allocate a three dimensional array. (The first dimension can be
1, so new [1][2][3] would do the trick, and effectively only
allocate a single [2][3].)
A better solution might be to wrap the array in a struct:
struct Array
{
int data[2][3];
};
You can then use new Array, and everything works as expected.
Except that the syntax needed to access the array will be
different.

double pointers to class

I remember seeing this line of code on my final exam, still to this day I can't figure it out or a use for it. I tired googling "double pointers" and "Pointer to Array of Classes" and still can't find an answer.
I want to know why you would use something like this (practical use) or direct me to a website that explain this for me. Thank you.
vendingMachine **va = new vendingMachine*[numMachines];
It doesn't really matter that the type involved is a class. It could just as well be a basic type:
int **va = new int*[numInts];
The semantics are the same. You have a pointer that points to a pointer. Since dynamically allocated arrays are implemented with pointers, this becomes an array of pointers. Here is a use case:
int a, b;
va[0] = &a;
va[1] = &b;
But since, as mentioned, you can implement arrays with pointers, you can also treat it as an array of arrays. So you have another use case:
va[0] = new int[10];
va[1] = new int[10];
// ...
va[numInts - 1] = new int[10];
va[0][0] = 2;
va[0][1] = 8;
// ...
va[numInts - 1][9] = 3;
So you have an array of arrays. Or in other words, a two dimensional array of ints. If you now change back from int to vendingMachine, you'd have a 2D array of vendingMachine objects.

Why does the debugger show only one element from my array pointer?

First off: I know that new is the C++ way of doing this. I am simply showing that there is more than one way to reproduce this error, and both are incredibly frustrating.
I have two forms of this source file. I'm trying to debug yet another programming assignment, but I'm not asking for help on that. Basically, I'm trying to re-implement set as a class with fields for size and a pointer to an int array. Here's the code using new:
testnew.cpp
int main()
{
int size = 1;
int *elements = new int[size];
elements[0] = 0;
size++;
int * temp = new int[size];
for (int i = 0; i < (size - 1); i++)
{
temp[i] = elements[i];
}
delete[] elements;
temp[size] = size;
elements = temp;
elements[1] = 1;
delete[] elements;
}
and again, using the less-preferable alloc functions:
testalloc.cpp
int main()
{
int size = 1;
int * elements = (int *) malloc(sizeof(int) * size);
elements[0] = 0;
size++;
elements =(int *) realloc(elements,size * sizeof(int));
elements[1] = 1;
free(elements);
}
In both cases, my goal is to create an array, and then append to it. However, in both cases, after building and running it in Visual Studio 2010, the array is not grown at all, and only has 1 "slot" for my items to go into. In VS's debugger, I have watches on the elements array pointer; attached is a screenshot. It is the same for both versions of the code.
-- the breakpoint is at the delete[]/free() call.
Seriously, what am I doing wrong? This has to be a logic error, and I've combed through a quarter dozen examples of both malloc/realloc and new, and read and re-read my textbook, and I can't see what's wrong!
I feel like I should have a line that splits the allocated memory into an array, but doesn't the new int[] call do that?
Besides any other issues with the code, you must either do what JoeG mentions and have multiple watches, or set a watch like this:
elements,5
will result in:
I don't know if there is an updated list for VS2010, but this still works:
Symbols for Watch Variables
And:
View array in Visual Studio debugger?
Other answers have pointed out the bug in your code (temp[size] = size;), however your confusion is coming from the fact that you're misreading the debugger's output.
As far as the type system and debugger are concerned, elements isn't an array, it's a pointer. The debugger has no way of knowing whether or not it's a pointer to the first element in an array or a pointer to a single element.
If you want to see the value of elements[x] in your debugger, use the expression *(elements+x).
In the first example, this is wrong:
temp[size] = size;
This will translate to:
temp[2] = 2;
And since arrays are zero-indexed you are writing outside your allocated area.
First of all C++ is 0 indexed, so temp[size] = size; is an off by one error. And to answer your question, the type of elements is int*. That it's actually an array is not knowledge which is available to VS without code analysis. So, what you need to do is either use for example std::vector<>, boost::array or make sure that your array never detoriates to int*.
The file testnew.cpp allocates memory for size elements in temp but then sets temp[size], which is the size+1 element. Perhaps this should be
temp[i] = size;
The file testalloc.cpp commits the common error of reassigning memory to the same variable without verifying that thte call to realloc succeeds:
elements =(int *) realloc(elements,size * sizeof(int));
If realloc fails, elements will be set to null, and its original memory will be orphaned.

The right way to create pointer to pointer object?

What is the right way to create a pointer to pointer object? Like for example,
int **foo;
foo = new int[4][4];
Then the compiler gives me an error saying "cannot convert from int (*)[4] to int **.
Thanks.
int **foo = new int*[4];
for (int i = 0; i < 4; i++)
foo[i] = new int[4];
Clarification:
In many languages the code above is called a jagged array and it's only useful when the "rows" have different sizes. C++ has no direct language support for dynamically allocated rectangular arrays, but it's easy to write it yourself:
int *foo = new int[width * height];
foo[y * height + x] = value;
Using raw new is a bit unwieldy to use. The inner dimension (last 4) must be a compile time constant, in addition. You also have to remember to delete the array once you are finished using it.
int (*foo)[4] = new int[4][4];
foo[2][3] = ...;
delete[] foo;
If that feels too "syntactic braindead", you can use typedef to prettify it
typedef int inner_array[4];
inner_array *foo = new int[4][4];
foo[2][3] = ...;
delete[] foo;
That's called a rectangular 2-dimensional array, because all the rows (4 of them, which can be determined at runtime) have the same width (which must be known at compile time).
Alternatively, use std::vector, with which you don't need to mess around with delete anymore, and which will also handle the raw pointer mess:
std::vector<int> v(4 * 4);
v[index] = ...;
You may later add or remove integers from the vector as you wish. You could also create a vector< vector<int> >, but i find it unwieldy to use, because you have to manage the separate row-vectors (which can be of varying lengths), and they are not seen as "one unit" together.
You can always create a function that maps a two dimensional coordinate to a one-dimensional index
inline int two_dim(int x, int y) {
return y * 4 + x;
}
v[two_dim(2, 3)] = ...;
For a simple two-dimensional array whose size you know beforehand, you don't need new at all, though
int x[4][4];
x[2][3] = ...;

C++ - is a pointer to a single value same as a size 1 dynamic array?

I have this snippet of code which I am considering to simplfy:
if (numberOfResults > 1)
{
trackResult_ = new TrackResult[numberOfResults];
for (int i=0; i < numberOfResults; i++)
{
// Make a deep copy
TrackResult tempResult = result[i];
TrackResult * clone = new TrackResult(tempResult);
trackResult_[i] = *clone;
}
storeJointResults(trackResult_, numberOfResults);
}
else
{
trackResult_ = new TrackResult(*result);
}
(I have 'no choice' but to use a simple dynamic array here. Vectors are deemed 'too complicated' at my workplace)
I am wondering if I can get away with
// even if we just have one result, we init an array size of one
trackResult_ = new TrackResult[numberOfResults];
However, I have in several points check for the number of results and act accordingly
if (numberOfResults_ == 1)
{
velocity = trackResult_.velocity;
}
Would those code still work? If not, why?
The array of size 1 does not need to be a special case.
When you allocate a dynamic array you are given a pointer to the first element. If the array is of size 1, this is pretty much indistinguishable from just having allocated a single instance of the object.
Your special case usage would work if you changed the . to an ->
However I'd recommend not special-casing it and just use trackResult_[0].velocity
No, you need to ensure you match the correct scalar delete or array delete[] depending on whether you say new TrackResult[n]; or new TrackResult;.
Also, this leaks memory for each loop iteration:
TrackResult tempResult = result[i];
TrackResult * clone = new TrackResult(tempResult);
TrackResult_[i] = *clone;
How are vectors too complicated? If anything, the simplify your code.
I agree with Alex, using the . operator on a pointer is not my recommended style either, so those other points ought to be changed anyhow, and thus not discourage you from simplifying the piece of code you mention.