I am trying to work with a multi-dimensional array in MSVS2010 console application, and I need to access members of a 2D array. I instantiate the array as
Thing::Thing(int _n){
// size of the array
this.m = _n;
thing = new int*[m];
for(int ii = 0; ii < m; ii++){
thing[ii] = new int[m];
}
}
this is working fine. though when I go to do a operator=, or operator== that both use the similar structure of:
Thing& Thing::operator=(const Thing & _thing){
for(int ii = 0; ii < m; ii++){
for(int jj = 0; jj < m; jj++){
thing[ii][jj] = _thing[ii][jj]; //error thrown on this line
}
}
return *this;
}
this throws 2 errors
binary "[": 'const Thing' does not define this operator or a conversion to a type acceptable to the predefined operator
IntelliSense: no operator"[]" matches these operands
this doesn't make sense as it is an array of type int, and the "[]" operators have not been altered not to mention that error highlighting only puts it under:
_thing[ii][jj];
I can kinda live without the assignment operator, but I need the comparison operator to have functionality.
You should do: thing[ii][jj] = _thing.thing[ii][jj]; in your assignment loop. And you should also check if the array sizes for both (this and _thing) are the same: it may give a crash otherwise.
You get an error because you are trying to use operator[] (indexing operator) on an object class Thing, not on its internal array. If you want to use the Thing class like an array you should define an indexing operator for it e.g.:
int* Thing::operator[](int idx)
{
return thing[idx];
}
I think you've got your "thing"-s confused. Since:
Thing& Thing::operator=(const Thing & _thing)
you probably want to have:
thing[ii][jj] = _thing.thing[ii][jj];
_thing is the Thing object
_thing.thing is the multidimensional array
Thing is the class, thing is the member, thing the parameter... and you forgot that if you want to access the member in the operator= call then you should use _thing.thing.
Your naming choice is quite bad, so bad that it even confused yourself while you were writing the code (and if it was easy for you to make a mistake now try to imagine how much easier would be for someone else to get confused by this code or even for you in a few months from now).
What about calling for example the class Array instead, the member data and the parameter other? I also would suggest avoiding having leading underscores in names, they are ugly and dangerous at the same time (do you know all the C++ rules about where you can put underscores in names and how many of them you are allowed to use?).
When designing a class or a function you have many things to consider and the class name or the function name is important but is one of the many factors. But for a data member or a variable you only have to choose the type and the name and both of them are most important choices.
So please take the habit of thinking carefully to names, especially of variables. The relative importance is tremendous for them. Variables and data members are just names... the name is actually the only reason for which in programming we like to use variables (the computer instead only uses numeric addresses and is perfectly happy with them).
About the class design you probably would also like defining operator[](int)...
int *operator[](int index) { return data[index]; }
By doing this you will be able to write code like
Array a(m);
a[0][0] = 42;
without the need to explicitly refer to data (and, by the way, this addition would also make your original code working... but still fix the names!!).
Related
I've been attempting to reassign a particular vector element to a new value and received a error from the compiler, and I'm not sure I understand it. So I believed that you could reassign a single vector element in the same way you could reassign an array's element.
std::vector<int> myVector[10];
myVector[5] = 6;
Or you could alternatively use the built in '.at' to access the vector with bounds checking. When I was writing some trivial code just to understand some concepts better I ran across a peculiar situation.
int main()
{
std::vector<int> test[10];
test[3] = 5;
if (test[3] != 6)
{
std::cout << "It works!" << std::endl;
}
return 0;
}
Now this piece of code flags an error saying that the assignment operator '=' and the logical operator '!=' doesn't match based on these operands. Now if I use the arrow operator '->' the code works just fine. Which is good, but I thought, perhaps mistakenly, that the arrow operator was used when dereferencing a pointer-to-object. I attempted to google these results, but perhaps due to the very rudimentary nature of it, I couldn't find much on the topic. Although, I would like to mention on a few sites with "c++ tutorials" I did see that they used the assignment operator without dereferencing the vector. Now this happens in both Visual Studios 2017 as well as the most recent version of Code::Blocks. Was I wrong? Do you actually need to utilize the arrow operator? Or am I missing something even more basic?
You created an array of 10 vectors, not a vector of 10 elements. A vector is is ultimately a class type, so you need to initialize it via a constructor:
std::vector<int> test(10);
The way you did it originally, meant you tried to assign the value 5 for the vector at index 3. Vectors don't support being assigned numbers, so that's what the error is about.
You're declaring an array of vectors rather than one vector of some initial length. Use the following instead of your declaration:
std::vector<int> myVector(10);
I wanted to create a function that would define an 1d Array, calculate a sum of the elements, and display that sum. I wrote the following code however I'm unaware of the use of pointers and other advanced techniques of coding.
#include <iostream>
using namespace std;
int main()
{
int size;
int A[];
cout << "Enter an array: \n";
cin << A[size];
int sum;
int sumofarrays(A[size]);
sum = sumofarrays(A[size]);
cout << "The sum of the array values is: \n" << sum << "\n";
}
int sumofarrays(int A[size])
{
int i;
int j = 0;
int sum;
int B;
for (i=0; i<size; i++)
{
B = j + A[i];
j = B;
}
sum = B;
return(sum);
}
When attempting to compile this code, I get following error:
SumOfArrays.cpp:19:18: error: called object type 'int' is not a
function or function pointer sum = sumofarrays(size)
If only you had used a container like std::vector<int> A for your data. Then your sum would drop out as:
int sum = std::accumulate(A.begin(), A.end(), 0);
Every professional programmer will then understand in a flash what you're trying to do. That helps make your code readable and maintainable.
Start using the C++ standard library. Read a good book like Stroustrup.
Please choose Bathsheba's answer - it is the correct one. That said, in addition to my comment above, I wanted to give some more tips:
1) You need to learn the difference between an array on the stack (such as "int A[3]") and the heap (such as a pointer allocated by malloc or new). There's some degree of nuance here, so I'm not going to go into it all, but it's very important that you learn this if you want to program in C or C++ - even though best practice is to avoid pointers as much as possible and just use stl containers! ;)
2) I'm not going to tell you to use a particular indentation style. But please pick one and be consistent. You'll drive other programmers crazy with that sort of haphazard approach ;) Also, the same applies to capitalization.
3) Variable names should always be meaningful (with the possible exception of otherwise meaningless loop counters, for which "i" seems to be standard). Nobody is going to look at your code and know immediately what "j" or "B" are supposed to mean.
4) Your algorithm, as implemented, only requires half of those variables. There is no point to using all of those temporaries. Just declare sum as "int sum = 0;" and then inside the loop do "sum += A[i];"
5) Best practice is - unlike the old days, where it wasn't possible - to declare variables only where you need to use them, not beforehand. So for example, you don't need to declare B or j (which, as mentioned, really aren't actually needed) before the loop, you can just declare them inside the loop, as "int B = j + A[i];" and "int j = B;". Or better, "const int", since nothing alters them. But best, as mentioned in #4, don't use them at all, just use sum - the only variable you actually care about ;)
The same applies to your for-loop - you should declare i inside the loop ("for (int i = ....") rather than outside it, unless you have some sort of need to see where the loop broke out after it's done (not possible in your example).
6) While it really makes no difference whatsoever here, you should probably get in the habit of using "++i" in your for-loops rather than "i++". It really only matters on classes, not base types like integers, but the algorithms for prefix-increment are usually a tad faster than postfix-increment.
7) You do realize that you called sumOfArrays twice here, right?
int sum;
int sumofarrays(A[size]);
sum = sumofarrays(A[size]);
What you really meant was:
const int sum = sumofarrays(A);
Or you could have skipped assigning it to a variable at all and just simply called it inside your cout. The goal is to use as little code as possible without being confusing. Because excess unneeded code just increases the odds of throwing someone off or containing an undetected error.
Just don't take this too far and make a giant mishmash or trying to be too "clever" with one-liner "tricks" that nobody is going to understand when they first look at them! ;)
8) I personally recommend - at this stage - avoiding "using" calls like the plague. It's important for you to learn what's part of stl by having to explicitly call "std::...." each time. Also, if you ever write .h files that someone else might use, you don't want to (by force of habit) contaminate them with "using" calls that will have an effect on other peoples' code.
You're a beginner, that's okay - you'll learn! :)
In C (or C++), is it possible to create an array a (or something that "looks like" an array), such that a[0], a[1], etc., all point to the same memory location? So if you do
a[0] = 0.0f;
a[1] += 1.0f;
then a[0] will be equal to 1.0f, because it's the same memory location as a[1].
I do have a reason for wanting to do this. It probably isn't a good reason. Therefore, please treat this question as if it were asked purely out of curiosity.
I should have said: I want to do this without overloading the [] operator. The reason for this has to do with avoiding a dynamic dispatch. (I already told you my reason for wanting to do this is probably not a good one. There's no need to tell me I shouldn't want to do it. I already know this.)
I suppose a class like this is what you need
template <typename T>
struct strange_array
{
T & operator [] (int) { return value; }
private:
T value;
};
You can always define an array of pointers which points towards the same variable :
typedef int* special;
int i = 0;
unsigned int var = 0xdeadbeef;
special arr[5];
for (i=0; i<5; i++)
arr[i] = &var;
*(arr[0]) = 0;
*(arr[3]) += 3;
printf("%d\n", *(arr[2]));
// -> 3
In C, I don't think so.
The expression a[i] simply means *(a + i), so it's hard to avoid the addition due to the indexing.
You might be able to glue something together by making a (the array name) a macro, but I'm not sure how: you wouldn't have access to the index in order to compensate for it.
Without overloading operator[]?
No, it's not possible.
Fortunately.
From all that conversation here, I now understand the problem as follows:
You want to have the syntax of an array, e.g.
a[n] // only lookup
a[n]++ // lookup and write
but you want to have the semantics changed to all of those map to the same element, like
a[0]
a[0]++
The C++ way to achieve this is IMHO to overload the index access operator [].
But, you don't want it for performance reasons.
I join the opinon of user Lightness Races in Orbit that you can not do this within C++.
As you don't provide more information about the use case it is hard to come up with a solution.
Best I can imagine is that you have lots of written code which uses array semantics which you can not change.
What is left (wanting to keep performance) are code transformation techniques (CPP, sed, ..), generating a source code from the given source code with the desired behaviour, e.g. by forcing all index values to 0.
Should I be worried about having too many levels of vectors in vectors?
For example, I have a hierarchy of 5 levels and I have this kind of code
all over my project:
rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d]
where each element is a vector. The whole thing is a vector of vectors of vectors ...
Using this still should be lot faster than copying the object like this:
Block b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
// use b
The second approach is much nicer, but slower I guess.
Please give me any suggestion if I should worry about performance issues related to this,
or else...
Thanks
Efficiency won't really be affected in your code (the cost of a vector random access is basically nothing), what you should be concerned with is the abuse of the vector data structure.
There's little reason that you should be using a vector over a class for something as complex as this. Classes with properly defined interfaces won't make your code any more efficient, but it WILL make maintenance much easier in future.
Your current solution can also run into undefined behaviour. Take for example the code you posted:
Block b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
Now what happens if the vector indexes referred to by pos.a, pos.b, pos.c, pos.d don't exist in one of those vectors? You'll go into undefined behaviour and your application will probably segfault (if you're lucky).
To fix that, you'll need to compare the size of ALL vectors before trying to retrieve the Block object.
e.g.
Block b;
if ((pos.a < rawSheets.size()) &&
(pos.b < rawSheets[pos.a].countries.size()) &&
(pos.c < rawSheets[pos.a].countries[pos.b].cities.size()) &&
(pos.d < rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks.size()))
{
b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
}
Are you really going to do that every time you need a block?!!
You could do that, or you can, at the very least, wrap it up in a class...
Example:
class RawSheet
{
Block & FindBlock(const Pos &pos);
std::vector<Country> m_countries;
};
Block & RawSheet::FindBlock(const Pos &pos)
{
if ((pos.b < m_countries.size()) &&
(pos.c < m_countries[pos.b].cities.size()) &&
(pos.d < m_countries[pos.b].cities[pos.c].blocks.size()))
{
return m_countries[pos.b].cities[pos.c].blocks[pos.d];
}
else
{
throw <some exception type here>;
}
}
Then you could use it like this:
try
{
Block &b = rawSheets[pos.a].FindBlock(pos);
// Do stuff with b.
}
catch (const <some exception type here>& ex)
{
std::cout << "Unable to find block in sheet " << pos.a << std::endl;
}
At the very least, you can continue to use vectors inside the RawSheet class, but with it being inside a method, you can remove the vector abuse at a later date, without having to change any code elsewhere (see: Law Of Demeter)!
Use references instead. This doesn't copy an object but just makes an alias to make it more usable, so performance is not touched.
Block& b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
(watch the ampersand). When you use b you will be working with the original vector.
But as #delnan notes you should be worried more about your code structure - I'm sure you could rewrite it in a more appropriate and maintable way.
You should be worried about specific answers since we don't know what the constraints are for your program or even what it does?
The code you've given isn't that bad given what little we know.
The first and second approaches you've shown are functionally identical. Both by default will return an object reference but depending on assignment may result in a copy being made. The second certainly will.
Sasha is right in that you probably want a reference rather than a copy of the object. Depending on how you're using it you may want to make it const.
Since you're working with vectors, each call is fixed time and should be quite fast. If you're really concerned, time the call and consider how often the call is made per second.
You should also consider the size of your dataset and think about if another data structure (database perhaps) would be more appropriate.
Having problems with array of pointers.
I have a custom class called C. C has a variable double c1. I have to sort an array of C-s by c1 using a custom written sorting algorithm. I am guessing that since I have to move objects in array, it would be much more eficient to just move pointers to objects, therefore I have to use not an array of objects, but an array of pointers to objects.
I initialized the array like that:
C** someC;
someC = new C*[size];
for(int i = 0; i < size; i++) {
// a and b are of type CPoint
someC[i] = new C(a,b);
}
Am I doing this part correctly? It is the calling of C objects that then causes problems:
someC[i]->a.x
gives me an error: left of '->a' must point to class/struct/union/generic type
I am new to C++ so I may be missing something obvious, but I did some research and did not find anything. Maybe I am not understanding well how pointers work...
UPDATE
The header file of C class:
#pragma once
class C
{
public:
CPoint a;
CPoint b;
double c1;
C(void);
C(CPoint,CPoint);
~C(void);
};
the implementation:
#include "StdAfx.h"
#include "C.h"
#include <math.h>
C::C(void)
{
}
C::C(CPoint a, CPoint b)
{
this->a=a;
this->b=b;
double c1_x = a.x - b.x;
double c1_y = a.y - b.y;
c1= sqrt( (c1_x * c1_x) + (c1_y * c1_y));
}
C::~C(void)
{
}
UPDATE
The problem was in the code I provided in the comments, I did not notice I was calling the array in a wrong way like this:
pDC->MoveTo(someC[i]->a.x, someC->a.y)
So the second call was incorrect. Thank you all for your help
Philosophy aside, this is pretty telling from your comment (emphasis added):
"I am actually calling someC in OnDraw method like that: pDC->MoveTo(someC[i]->a.x, someC->a.y); someC is defined as public in the header file"
Specifically, this in your parameter list :
someC[i]->a.x, someC->a.y
This tells me one of these is wrong. Judging by your error, I'm going to go with the first one. It would solidify that if we could see the definition of your object that is implementing OnDraw() and where exactly it is getting someC from.
If someC is a C* in your containing object, the second parameter is correct, the first is wrong.
If someC is a C** in your contained object then the first parameter is correct and the second is wrong.
Unless your C objects are really really expensive to copy construct, don't bother implementing your custom sort algorithm, but define a strict total order over C:
bool operator<(C const& lhs, C const& rhs) {
return lhs.c1 < rhs.c1;
}
and use std::sort on an std::vector<C>. If you do worry about copy construction overhead, you can also directly use an std::set<C> which automatically sorts itself, without copy construction.
After your Edit: Your C seems relatively small and easy to copy, but it's borderline; Your best bet is to give both approaches (set and vector) and benchmark which one is faster.
If your type contains just a double I'd guess that it would be much faster not to use pointers! If the objects contain a std::string or a std::vector<T> (for some time T) the picture probably changes but compared to moving a structure with one or two basic objects, the cost of accessing more or less randomly distributed data is fairly high. Of course, to determine the specific situation you would need to profile both approaches.