Error overloading operator [] for a std vector object - c++

I have a polygon class defined like this:
#include <gVector3.h> // an array containing three floats (x,y,z coordinates)
#include <vector>
class Polygon {
private:
std::vector <gVector3> vertices;
std::vector <gVector3> color;
I overloaded the [] operator for this class like so
gVector3 Polygon::operator [](unsigned int i) const {
return vertices[i];
}
I've written a simple test case:
gVector3 v1(0,0,1), v2(1,1,1), v3(2,0,1);
Polygon *p = new Polygon();
p->push(v1);
p->push(v2);
p->push(v3);
assert(p[0] == v1); // Assume == for the gVector3 class has been defined correctly
Push is defined like so..
void Polygon::push(gVector3 vec){
this->vertices.push_back(vec);
}
Bottom line is that this assertion fails, and I'm not sure why. Perhaps I'm misusing the Vector classes indexing method?
Any insights would be helpful!

p is a pointer, so p[0] is the Polygon that it points to. I'm surprised that it compiled; I guess there must be some strange implicit type conversion.
You almost certainly don't want to be messing around with pointers and new:
Polygon p;
p.push(v1);
p.push(v2);
p.push(v3);
assert(p[0] == v1);
but if you do for some reason, then you'll need to dereference the pointer before applying []
assert((*p)[0] == v1);

p[0] is equivalent to *(p + 0), or just *p, so its just giving you the Polygon object you allocated. You aren't calling operator[] on that object. You need to do (*p)[0] instead, which will first get you the Polygon object and then call operator[] on it.

Related

Implement matrix as a class in C++

I need to implement matrix as a class in C++.
This is my class:
class {
private:
int rows, columns;
int **mat;
};
In the main, I need to start the matrix in the regular way. For example : m[0][0]=1;
I thought to overloading the operator[][] but it is forbidden.
I would like to get some help. thanks.
Instead, you could overload the function call operator (operator()()), to get something like this:
int operator()(int p_row, int p_column);
which is legal and clean. I would allow you to write something like this:
// Create and fill in matrix called 'm'...
int matrixElement = m(0, 0); // get element m[0][0]
// ...
Here is an example of how to overload this operator.
Let's say we have vector<vector<int>> xThe operator [][] is really (ignoring out of bounds) vector<int> b = x[0] then int = b[0] combined into one line. I.e accessing the first array then the subscript operator of the second.
Hope this helps.
You can store the data in a continuous array using std::vector and then supply your own indexing operator which returns a pointer to the beginning of the row.
class Matrix
{
int rows, columns;
std::vector<int> data;
public:
/*...*/
// The overloaded operator[] returns a pointer to the beginning
// of the requested row, which can then be indexed for the column
// without checking the boundaries.
int* operator[](int r){
return &data[r*columns];
}
};
Using a vector of vectors is less efficient because the data gets spread to different memory locations. If you need bounds checking you can wrap the pointer in your own class and overload its operator[].

dynamic arrays and operator overloading cause memory crash

To illustrate my problem I minimalize my source:
#include <iostream>
class vec{
public:
float* X;
int DIM;
vec(int dimension)
{
DIM = dimension;
X = new float[dimension];
for (int i=0;i<DIM;i++)
X[i] = (float) rand()/RAND_MAX;
}
~vec(void){
delete [] X;
}
vec operator-( vec const& rhs )
{
vec ans(DIM);
for (int i=0;i<DIM;i++)
ans.X[i] = X[i] - rhs.X[i];
return ans;
}
};
int main(){
vec A(5),B(5),C(5);
C= A-B;
return 0;
}
When I execute this program I get an error that a heap was destroyed. I am pretty sure that the destructor is my problem. In the line with C= A-B; the variable ans will be destroyed by the constructor and cannot be returned. Is that right?
If I delete the line delete [] X; everything is ok. But it won't free up the memory.
I did my homework and consult one of the most famous search engine for this problem but didn't find any answer. How can I fix it?
C = A-B calls the default copy-assignment operator (as you haven't defined one). Therefore two different objects will point to the same dynamically-allocated array.
You need to read up on the Rule of Three (in a nutshell: if you define any of the destructor, the copy constructor or the copy-assignment operator, you probably need to define them all).
But preferably, you should avoid using raw arrays entirely; use a container type that manages its own memory.

How to index and assign elements in a tensor using identical call signatures?

OK, I've been googling around for too long, I'm just not sure what to call this technique, so I figured it's better to just ask here on SO. Please point me in the right direction if this has an obvious name and/or solution I've overlooked.
For the laymen: a tensor is the logical extension of the matrix, in the same way a matrix is the logical extension of the vector. A vector is a rank-1 tensor (in programming terms, a 1D array of numbers), a matrix is a rank-2 tensor (a 2D array of numbers), and a rank-N tensor is then simply an N-D array of numbers.
Now, suppose I have something like this Tensor class:
template<typename T = double> // possibly also with size parameters
class Tensor
{
private:
T *M; // Tensor data (C-array)
// alternatively, std::vector<T> *M
// or std::array<T> *M
// etc., or possibly their constant-sized versions
// using Tensor<>'s template parameters
public:
... // insert trivial fluffy stuff here
// read elements
const T & operator() (size_t a, size_t b) const {
... // error checks etc.
return M[a + rows*b];
}
// write elements
T & operator() (size_t a, size_t b) {
... // error checks etc.
return M[a + rows*b];
}
...
};
With these definitions of operator()(...), indexing/assign individual elements then has the same call signature:
Tensor<> B(5,5);
double a = B(3,4); // operator() (size_t,size_t) used to both GET elements
B(3,4) = 5.5; // and SET elements
It is fairly trivial to extend this up to arbitrary tensor rank. But what I'd like to be able to implement is a more high-level way of indexing/assigning elements:
Tensor<> B(5,5);
Tensor<> C = B( Slice(0,4,2), 2 ); // operator() (Slice(),size_t) used to GET elements
B( Slice(0,4,2), 2 ) = C; // and SET elements
// (C is another tensor of the correct dimensions)
I am aware that std::valarray (and many others for that matter) does a very similar thing already, but it's not my objective to just accomplish the behavior; my objective here is to learn how to elegantly, efficiently and safely add the following functionality to my Tensor<> class:
// Indexing/assigning with Tensor<bool>
B( B>0 ) += 1.0;
// Indexing/assigning arbitrary amount of dimensions, each dimension indexed
// with either Tensor<bool>, size_t, Tensor<size_t>, or Slice()
B( Slice(0,2,FINAL), 3, Slice(0,3,FINAL), 4 ) = C;
// double indexing/assignment operation
B(3, Slice(0,4,FINAL))(mask) = C; // [mask] == Tensor<bool>
.. etc.
Note that it's my intention to use operator[] for non-checked versions of operator(). Alternatively, I'll stick more to the std::vector<> approach of using .at() methods for checked versions of operator[]. Anyway, this is a design choice and besides the issue right now.
I've conjured up the following incomplete "solution". This method is only really manageable for vectors/matrices (rank-1 or rank-2 tensors), and has many undesirable side-effects:
// define a simple slice class
Slice ()
{
private:
size_t
start, stride, end;
public:
Slice(size_t s, size_t e) : start(s), stride(1), end(e) {}
Slice(size_t s, size_t S, size_t e) : start(s), stride(S), end(e) {}
...
};
template<typename T = double>
class Tensor
{
... // same as before
public:
// define two operators() for use with slices:
// version for retrieving data
const Tensor<T> & operator() (Slice r, size_t c) const {
// use slicing logic to construct return tensor
...
return M;
{
// version for assigning data
Sass operator() (Slice r, size_t c) {
// returns Sass object, defined below
return Sass(*this, r,c);
}
protected:
class Sass
{
friend class Tensor<T>;
private:
Tensor<T>& M;
const Slice &R;
const size_t c;
public:
Sass(Tensor<T> &M, const Slice &R, const size_t c)
: M(M)
, R(R)
, c(c)
{}
operator Tensor<T>() const { return M; }
Tensor<T> & operator= (const Tensor<T> &M2) {
// use R/c to copy contents of M2 into M using the same
// Slice-logic as in "Tensor<T>::operator()(...) const" above
...
return M;
}
};
But this just feels wrong...
For each of the indexing/assignment methods outlined above, I'd have to define a separate Tensor<T>::Sass::Sass(...) constructor, a new Tensor<T>::Sass::operator=(...), and a new Tensor<T>::operator()(...) for each and every such operation. Moreover, the Tensor<T>::Sass::operators=(...) would need to contain much of the same stuff that's already in the corresponding Tensor<T>::operator()(...), and making everything suitable for a Tensor<> of arbitrary rank makes this approach quite ugly, way too verbose and more importantly, completely unmanageable.
So, I'm under the impression there is a much more effective approach to all this.
Any suggestions?
First of all I'd like to point out some design issues:
T & operator() (size_t a, size_t b) const;
suggests you can't alter the matrix through this method, because it's const. But you are giving back a nonconst reference to a matrix element, so in fact you can alter it. This only compiles because of the raw pointer you are using. I suggest to use std::vector instead, which does the memory management for you and will give you an error because vector's const version of operator[] gives a const reference like it should.
Regarding your actual question, I am not sure what the parameters of the Slice constructor should do, nor what a Sass object is meant to be (I am no native speaker, and "Sass" gives me only one translation in the dictionary, meaning sth. like "impudence", "impertinence").
However, I suppose with a slice you want to create an object that gives access to a subset of a matrix, defined by the slice's parameters.
I would advice against using operator() for every way to access the matrix. op() with two indices to access a given element seems natural. Using a similar operator to get a whole matrix to me seems less intuitive.
Here's an idea: make a Slice class that holds a reference to a Matrix and the necessary parameters that define which part of the Matrix is represented by the Slice. That way a Slice would be something like a proxy to the Matrix subset it defines, similar to a pair of iterators which can be seen as a proxy to a subrange of the container they are pointing to. Give your Matrix a pair of slice() methods (const and nonconst) that give back a Slice/ConstSlice, referencing the Matrix you call the method on. That way, you can even put checks into the method to see if the Slice's parameters make sense for the Matrix it refers to. If it makes sense and is necessary, you can also add a conversion operator, to convert a Slice into a Matrix of its own.
Overloading operator() again and again and using the parameters as a mask, as linear indices and other stuff is more confusing than helping imo. operator() is slick if it does something natural which everybody expects from it. It only obfuscates the code if it is used everywhere. Use named methods instead.
Not an answer, just a note to follow up my comment:
Tensor<bool> T(false);
// T (whatever its rank) contains all false
auto lazy = T(Slice(0,4,2));
// if I use lazy here, it will be all false
T = true;
// now T contains all true
// if I use lazy here, it will be all true
This may be what you want, or it might be unexpected.
In general, this can work cleanly with immutable tensors, but allowing mutation gives the same class of problem as COW strings.
If you allow for your Tensor to implicitly be a double you can return only Tensors from your operator() overload.
operator double() {
return M.size() == 1 ? M[0] : std::numeric_limits<double>::quiet_NaN();
};
That should allow for
double a = B(3,4);
Tensor<> a = B(Slice(1,2,3),4);
To get the operator() to work with multiple overloads with Slice and integer is another issue. I'd probably just use Slice and create another implicit conversion so integers can be Slice's, then maybe using the variable argument elipses.
const Tensor<T> & operator() (int numOfDimensions, ...)
Although the variable argument route is kind of a kludge best to just have 8 specializations for 1-8 parameters of Slice.

C++ Instantiation

I have Vector class, representing a 3D point, written as follows in Vector.h:
class Vector {
public:
float x,y,z;
Vector(float _x=0.0,float _y=0.0,float _z=0.0){x=_x;y=_y;z=_z;};
operator float *() { return &x;};
};
I also declare a extern vector<Vector>model_vertices; on model.h
On a model.cpp file I implement Vector.h and declare a std::vector<Vector>model_vertices; globally (yes, I know the vector/Vector thing is confusing, but I must use the Vector naming for consistency).
On model.cpp, when initializing the contents of this vector I use a for loop with the following content:
float X,Y,Z;
offFileStream>>X;
offFileStream>>Y;
offFileStream>>Z;
Vector v=new Vector(X,Y,Z);
model_vertices[loadVertexIndex]=v;
I get the following error:
error C2440: 'initializing' : cannot convert from 'Vector *' to 'Vector'
Why?
The error is on this line:
Vector v=new Vector(X,Y,Z);
v is of type Vector, but new Vector(X,Y,Z) returns a Vector*:
What you probably wanted instead is just:
Vector v(X,Y,Z);
As a side note, I didn't see you initialize a size for the model_vertices. So you may want to use push_back() instead.
It's not quite clear what you're trying to achieve, but perhaps you're overthinking this.
First off, please forget the keyword new. Just pretend it doesn't exist. (By the time you'll need it, you'll know enough C++ to realize that you can ignore this post.)
Second, you can improve your class constructor to use an initializer list:
Vector(float _x = 0.0, float _y = 0.0, float _z = 0.0)
: x(_x), y(_y), z(_z)
{ }
Third, to populate a vector, just insert temporaries directly:
std::vector<Vector> v;
float x, y, z;
while (get_values(x,y,z)) // or any sort of loop you like
{
v.push_back(Vector(x,y,z));
}
If you have a recent version of C++, you can use the more efficient emplacement instead:
v.emplace_back(x, y, z); // no temporary
Vector v=new Vector(X,Y,Z);
model_vertices[loadVertexIndex]=v;
should be
Vector *v=new Vector(X,Y,Z);
model_vertices[loadVertexIndex]=*v;
new() allocated from the heap and it returns a pointer to an object.
If you want to call the constructor and allocate on the stack, do this instead.
Vector v(X,Y,Z);
The new operator can only be used when asigning to a pointer. If you just want to have an object v of type vector then you should use:
Vector v(X,Y,Z);
If you would like to have a pointer to Vector object then you should use:
Vector *v=new Vector(X,Y,Z);

Why can't I push this object onto my std::list?

Just started programming in C++.
I've created a Point class, a std::list and an iterator like so:
class Point {
public:
int x, y;
Point(int x1, int y1)
{
x = x1;
y = y1;
}
};
std::list <Point> pointList;
std::list <Point>::iterator iter;
I then push new points onto pointList.
Now, I'm needing to iterate through all the points in pointList, so I need to loop using the iterator. This is where I get screwed up.
for(iter = pointList.begin(); iter != pointList.end(); iter++)
{
Point currentPoint = *iter;
glVertex2i(currentPoint.x, currentPoint.y);
}
Update
You guys were right, the problem isn't in my iterating the list. It appears the problem is when I am attempting to push something on to the list.
Exact error:
mouse.cpp: In function void mouseHandler(int, int, int, int)':
mouse.cpp:59: error: conversion fromPoint*' to non-scalar type `Point' requested
Those lines are:
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point currentPoint = new Point(x, y);
pointList.push_front(currentPoint);
}
What does it conversion between Point* to non-scalar type Point? I'm just trying to create new points and push them onto the list here.
That should be a valid bit of code.
#include <iostream>
#include <list>
class Point {
public:
int x, y;
Point(int x1, int y1)
{
x = x1;
y = y1;
}
};
int main()
{
std::list<Point> points;
points.push_back(Point(0, 0));
points.push_back(Point(1, 1));
points.push_back(Point(2, 2));
std::list<Point>::iterator iter;
for(iter = points.begin(); iter != points.end(); ++iter)
{
Point test = *iter;
std::cout << test.x << ", " << test.y << "; ";
}
std::cout << std::endl;
return 0;
}
Using this code:
jasons-macbook41:~ g++ test.cpp
jasons-macbook41:~ ./a.out
0, 0; 1, 1; 2, 2;
jasons-macbook41:~
Although I wouldn't create a temporary copy of the Point as your code does. I'd rewrite the loop like this:
for(iter = points.begin(); iter != points.end(); ++iter)
{
std::cout << iter->x << ", " << iter->y << "; ";
}
An iterator is syntactically similar to a pointer.
EDIT:
Given your new problem, drop the "new" from the construction line. That's creating a pointer to a Point, as opposed to a Point on the stack. This would be valid:
Point* temp = new Point(0, 0);
Or this:
Point temp = Point(0, 0);
And you'd be better off with the latter.
a few things..
Did you try iter->x and iter->y instead of copying the value?
the error you mention is hard to understand. You are not trying to get x and y via the iterator, you are copying the iterator data to a new point.
EDIT:
according to new information in the OP. You are trying to new into a non-pointer object and then trying to stuff the point into a vector that only accepts objects. You either have to make the vector a vector of pointers and remember to delete them afterwords or create the new point on the stack and copy them into the vector with a standard assign. Try this:
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point currentPoint = Point(x, y);
pointList.push_front(currentPoint);
}
If already have a function you want to apply to a whole list the std::for_each is the way to go, e.g.,
std::for_each(pointList.begin(), pointList.end(), myGreatFunction);
If you have to write the for loop then something like this:
std::list<Point>::iterator itEnd = pointList.end();
for(std::list<Point>::iterator itCur=pointList.begin(); itCur != itEnd; ++itCur) {
yourFunction(itCur->x, itCur->y);
}
Notes:
++itCur can be more efficient than itCur++ due to the return types (reference vs value/copy)
The non-scalar issue is because you're assigning a Point pointer (return value of operator new) to a Point stack object (as it's not Point* in your code).
I would recommend saying
Point currentPoint(x, y);
pointList.push_front(currentPoint);
Note that currentPoint will be copied into your list; the implicitly-generated copy constructor of Point (because you didn't declare a Point(const Point& other) constructor in your class, the compiler did one for you) will copy currentPoint.x and currentPoint.y into the list; in this case, that's fine. Point is small, so the copy expense is low, and it only contains two ints, so a straight up copying of ints is ok.
This answer refers to the edited version of the question.
As gbrandt said in the edited version of his answer, your problem is that you are trying to dynamically allocate an instance of Point and then assign it to a Point object rather than a pointer to Point. The result of new is a pointer to Point, not a Point object -- what you actually want in this case is the latter, which you create without new:
Point currentPoint(x, y);
pointList.push_front(currentPoint);
Because list<T>::push_front() pushes a copy of the Point object on the list, you don't need to do any dynamic allocation here. It's much safer to avoid dynamic allocation when possible as it can easily lead to memory leaks -- e.g. the following alternative code, which compiles and works, results in a memory leak as the object pointed to by currentPoint is never deleted:
Point *currentPoint = new Point(x, y);
pointList.push_front(*currentPoint); // Notice the "*"
Of course you could just add delete currentPoint; to the end to remove the leak, but why use slow dynamic allocation when stack-based allocation does the job faster and more simply?
Here's how I typically approach such loops, if you don't want to use std::foreach:
for (iter curr = pointListObject.begin(), end = pointListObject.end(); curr != end; ++curr)
{
glVertex2i(curr->x, curr->y);
}
Be careful of these points:
pointListObject is an instance of pointList; if you use the class (the type pointList, and not an instance of pointList) you're in troble, but the compiler will whine a lot. Same with iter. It just makes things easier to grok if you keep typenames and instancenames separate.
Doing a joint initialization of the iterators like this lets you keep the initialization of end inside the loop (good for scoping) while keeping the per-loop execution cheap.
Did you cut and paste this code into SO from your .cpp file, or did you retype it? From the sound of your error message, I would guess that the original code says
glVertex2i(iter.x, iter.y);
Which, as gbrandt pointed out, doesn't properly dereference the iterator.
I would rewrite the loop as follows:
std::list<Point>::const_iterator iter = pointList.begin();
const std::list<Point>::const_iterator end = pointList.end();
for (; iter != end; ++iter) {
const Point& p = *iter;
glVertex2i(p.x, p.y);
}
The main changes are to use const_iterators instead of non-const, as your loop doesn't intend to modify the list contents. Then, grab the values of begin() & end() exactly once, use preincrement, and dereference the iterator once into a const reference. This way you have no copying, where your original code copied the Point object that *iter referred to, and you avoid dereferencing the iterator twice for about as much efficiency as you can get here.
Now, for some unsolicited OpenGL advice, I'd also point out that vertex arrays are probably a better choice than immediate mode (glVertex*) calls.
Hope this helps...