C++: Variable length multidimensional array [duplicate] - c++

This question already has answers here:
Operator[][] overload
(17 answers)
Closed 8 years ago.
I need a two dimensional array where the length of neither dimension is known at compile time. I want [][] access.
There are several questions about this already, suggesting boost::multi_array, std::vector<std::vector<type>>, allocating one array for the x dimension and X arrays for the y dimension, so on and so forth.
The catch is that I do not control the data, it already exists as a single contiguous array (size x*y). I have a pointer to it and the size of both dimensions, and I am more or less wrapping it to get [][] access.
I would like to avoid creating a whole bunch of objects (like allocating an array of std::vectors and pointing them all at the right things), and boost.
I considered creating a class to hold both dimensions and the pointer, and overloading [][], but that doesn't work because [][] is two operators, and the second [] applies to a different object.
Ultimately I'm looking for something that amounts to using [][] as syntactic sugar for some kind of access(int x, int y) function. Is that possible?

You may wrap it in a class and overload operator [], something like:
template <typename T>
class MultiArray
{
public:
explicit MultiArray(T* arr, int sizex, int sizey) : data(arr), sizey(sizey) {}
const T* operator [] (int x) const { return &data[x * sizey]; }
T* operator [] (int x) { return &data[x * sizey]; }
private:
T* data;
int sizey;
};
Live example

You need to have two classes DataTypeP and DataTypePP. While initializing DataTypePP, you will need to distribute the memory chunks to different DataTypeP references.
class DataTypeP {
int *ptr;
public:
int operator[](int y){ return ptr[y];}
};
class DataTypePP{
DataTypeP *bPtr;
public:
DataTypeP operator[](int x){ return bPtr[x];}
};
int main(){
DataTypePP a;
cout<<a[1][2];
return 0;
}

With a std::vector<std::vector<type*>>, you can build the inside vector using custom input operator that iterate over your data and return a pointer to each data.
For example:
size_t w, h;
int* myData = retrieveData(&w, &h);
std::vector<std::vector<int*>> data;
data.reserve(w);
template<typename T>
struct myIterator : public std::iterator<std::input_iterator_tag, T*>
{
myIterator(T* data) :
_data(data)
{}
T* _data;
bool operator==(const myIterator& rhs){return rhs.data == data;}
bool operator!=(const myIterator& rhs){return rhs.data != data;}
T* operator*(){return data;}
T* operator->(){return data;}
myIterator& operator++(){data = &data[1]; return *this; }
};
for (size_t i = 0; i < w; ++i)
{
data.emplace_back(myIterator<int>(&myData[i * h]),
myIterator<int>(&myData[(i + 1) * h]));
}
Live example
This solution has the advantage of providing you with a real STL container, so you can use special for loops, STL algorithms, and so on.
for (const auto& i : data)
for (const auto& j : i)
std::cout << *j << std::endl;
std::cout << "or with index access: " << std::endl;
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
However, it does create vectors of pointers, so if you're using small datastructures such as this one you can directly copy the content inside the array.

Related

Sorting list of shared pointers

Given the class
class objects {
public:
bool compareArea (const objects& obj) const { return this->area < obj.area; }
private:
double area;
};
I want to sort a
list<shared_ptr<objects>> myObjects;
I cannot use a lambda (since my toolchain's C++11 support is incomplete). Thus, I tried the following:
using namespace placeholders;
myObjects.sort(bind(&objects::compareArea,_1,_2));
This line is called from another file (not from a class member!). The problem is, that compareArea requires two objects as input. But I give two shared pointer to objects to it. Is there an easy way of how to include the dereferencing of the pointers into the sort-call? I want the objects::compareArea(..) function to stay as it is. I do not want this kind of solution
bool compareArea (const shared_ptr<objects>& ptr1, const shared_ptr<objects>& ptr2) {
return ptr1->area > ptr2->area;
}
// in same source-file:
myObjects.sort(bind(compareArea,_1,_2));
where compareArea is no member-function of objects. Actually an operator overloading of < would be my favourite solution.
I would strongly suggest that you never store any kind of pointer in a container.
Instead, make a handle class which supports the required arithmetic and comparison operators.
It makes for code that's easier to reason about:
class objects {
public:
objects(double w, double h) : area(w * h) {}
bool operator<(const objects& r) const { return this->area < r.area; }
private:
double area;
};
struct object_handle
{
object_handle(shared_ptr<objects> const& ptr) : ptr_(ptr) {}
static object_handle create(double w, double h) { return make_shared<objects>(w,h); }
bool operator < (object_handle const& r) const {
return *ptr_ < *r.ptr_;
}
shared_ptr<objects> ptr_;
};
int main() {
std::vector<object_handle> mylist;
mylist.push_back(object_handle::create(10, 7));
mylist.push_back(object_handle::create(2, 5));
std::sort(mylist.begin(), mylist.end());
}
Lambdas are just syntactic sugar for a class with operator(), so you can very easily write one directly (especially if you don't need captures):
struct Comparator
{
bool operator() (const shared_ptr<objects> &lhs, const shared_ptr<objects> &rhs) const
{
return lhs->compareArea(*rhs);
}
};
myObjects.sort(Comparator());

Efficient vector operators in C++ / References to temporary objects

I am trying to write a C++ vector class that stores an array of data and allows performing mathematical operations on an element-by-element basis. I want to implement this in such a way that an expression a = b + c + d should loop over all elements only once and directly write the sum b[i] + c[i] + d[i] to a[i] without creating intermediate vectors.
I was writing something like this:
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
}
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
T& operator[] (int i) { return data[i]; }
T& const operator[] (int i) const { return data[i]; }
MyVector<T,N>& operator=(const VectorExpression<T,N> &rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
}
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
VectorExpression<T,N> &a, &b;
public:
VectorSum(VectorExpression<T,N> &aa, VectorExpression<T,N> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
}
template<class T, int N>
VectorSum<T,N> operator+(const VectorExpression<T,N> &a,
const VectorExpression<T,N> &b)
{
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,10> a, b, c, d;
// Initialize b, c, d here
a = b + c + d;
return 0;
}
Probably this functionality is provided by the valarray class but that's because I tried to strip it down to a minimal example.
I made operator[] virtual because this allows nesting all kinds of expressions (e.g. a = !(-b*c + d)) provided I would define all the operators and the corresponding classes similar to VectorSum.
I use references because ordinary variables aren't polymorphic and pointers don't work with operator overloading.
Now my questions about this are:
In the statement a = b + c + d;, two temporary VectorSum<double,10> objects will be created to store b + c and (b+c) + d respectively. Will they live long enough to make the polymorphic behavior work? More specifically, (b+c) + d will store a reference to b + c, but will that object still exist when operator= is called? According to this post all temporaries should exist until operator= returns, but does this also hold for older versions of C++?
If not, then how is this done? The only alternative I see would be to allocate the VectorSum objects using new, return them by reference and then delete them in the operator= functions, but that seems a little cumbersome, and probably a lot less efficient. I'm also not sure if it is always safe.
(Minor question) Is it okay to override the return type T of VectorExpression::operator[] by T& const in MyVector?
EDIT
I had wrong argument types in operator+: changed them from VectorSum to VectorExpression.
Well here's what I came up with:
#include <iostream>
#include <initializer_list>
#include <algorithm>
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) = 0;
virtual const T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
};
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
MyVector() {
// initialize zero
std::fill(std::begin(data), std::end(data), T());
}
MyVector(const std::initializer_list<T>& values) {
// initialize from array initializer_list
std::copy(std::begin(values), std::end(values), data);
}
MyVector(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
}
MyVector<T,N>& operator=(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
T operator[] (int i) { return data[i]; }
const T operator[] (int i) const { return data[i]; }
friend std::ostream& operator<<(std::ostream& stream, MyVector& obj) {
stream << "[";
for (int i = 0; i < N; ++i) {
stream << obj.data[i] << ", ";
}
stream << "]";
return stream;
}
};
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
const MyVector<T,N> &a, &b;
public:
VectorSum(const MyVector<T,N>& aa, const MyVector<T,N>& bb):
a(aa), b(bb) {
}
T operator[] (int i) { return return a[i] + b[i]; }
const T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,3> a, b({1,2,3}), c({3,4,5}), d({4,5,6});
a = b + c + d;
std::cout << b << std::endl;
std::cout << c << std::endl;
std::cout << d << std::endl;
std::cout << "Result:\n" << a << std::endl;
return 0;
}
Output:
[1, 2, 3, ]
[3, 4, 5, ]
[4, 5, 6, ]
Result:
[8, 11, 14, ]
I've added an initializer_list (C++11) constructor and ostream operators purely for convenience/illustration purposes.
Since you've defined the operator[] as return by value, I was unable to set items in the data array for testing (since error: lvalue required as left operand of assignment); typically this operator should be by reference - but then, in your case, VectorSum::operator[] wouldn't work because that would fail compilation because of returning a reference to a temporary.
I also added a copy constructor because ...
// this calls MyVector's copy constructor when assigned to 'main::a'
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b); // implicit MyVector::copy constructor
}
// this also calls MyVector's copy constructor (unless the copy constructor is defined explicit)
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res = VectorSum<T,N>(a, b);
return res;
}
// but this would call MyVector's assignment operator
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res;
res = VectorSum<T,N>(a, b);
return res;
}
In answer to your questions:
Yes - how would it behave if you explicitly defined the variable and
returned that? It's the same behaviour for temporaries, except there
is no variable declaration;
n/a
I touched on this above - you can't
use reference because of 'returning reference to temporary' error;
However there's no reason why you can add T& operator[] to MyVector( ie. not overriding).
EDIT: answers to comments:
The function specification must be identical when overriding including return type. Since you have defined it return by value in VectorExpression it must be return by value in MyVector. If you try to change it to reference in the child class you will get a compile error: conflicting return type specified. So no you can't override operator const with a version that returns const T& instead of T. Furthermore it must return by value since MyVectorSum returns { a[i] + b[i] } which would be a temporary and you can't return a reference to a temporary.
Sorry my mistake, fixed above.
because:
MyVector isn't a subtype of VectorSum - compile error ‘MyVector’ is not derived from ‘const VectorSum’
I've also tried with VectorExpression but compile error: 'cannot allocate an object of abstract type' - because it's trying to return by value
I chose MyVector since that's the type of your expected result. Yes it does those all those for loops but I can't see a way round that : there's three different array 'data' variables each of which need to be iterated into order to be accumulated. At some point in the code you will have to do the for loops.
Understood, yes I got confused. removed from post.
I didn't think of this at first but having a virtual operator[] method probably kills the efficiency I was trying to achieve by avoiding the 3 for-loops and intermediate storage of vector-sized temporaries. Making a method virtual prevents it from being inlined, which means it needs to be actually called as a function everytime an element is accessed.
Based on links I got from people who commented to my question and from Google, I ended up with the following solution which avoids needing any virtual methods.
template<class T, int N, class V>
class VectorExpressionBase {
V ref;
protected:
explicit VectorExpressionBase(const V *ref)
: ref(const_cast<V*>(ref)) {}
public:
T operator[] (int i) const { return ref[i]; }
T& operator[] (int i) { return ref[i]; }
};
template<class T, int N>
class VectorExpressionBase<T,N,void> {
T data[N];
protected:
explicit VectorExpressionBase(const void*) {
// Argument is unused but accepted to have uniform
// calling syntax
}
public:
T operator[] (int i) const { return data[i]; }
T& operator[] (int i) { return data[i]; }
};
template<class T, int N, class V>
class VectorExpression : public VectorExpressionBase<T,N,V> {
public:
template<class V1>
VectorExpression<T,N,V>& operator= (
const VectorExpression<T,N,V1> &rhs)
{
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
explicit VectorExpression(const V *ref = 0)
: VectorExpressionBase<T,N,V>(ref) {}
// Can define all kinds of operators and functions here such as
// +=, *=, unary + and -, max(), min(), sin(), cos(), ...
// They would automatically apply to MyVector objects and to the
// results of other operators and functions
};
template<class T, int N>
class MyVector : public VectorExpression<T,N,void> {
};
template<class T, int N, class VA, class VB>
class VectorSum {
VectorExpression<T,N,VA> &a;
VectorExpression<T,N,VB> &b;
public:
VectorSum(VectorExpression<T,N,VA> &aa, VectorExpression<T,N,VB> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N, class VA, class VB>
VectorExpression<T,N,VectorSum<T,N,VA,VB> >
operator+(const VectorExpression<T,N,VA> &a,
const VectorExpression<T,N,VB> &b)
{
VectorSum<T,N,VA,VB> sum(a, b);
return VectorExpression<T,N,VectorSum<T,N,VA,VB> >(sum);
}
Class VectorExpression now just wraps the class that does the work (in this case VectorSum). This allows defining all kinds of functions and operators for VectorExpression only, rather than having to overload them for VectorSum, VectorProduct, etc.
MyVector derives from a special case of VectorExpression which has a specialized base class; this isn't really necessary but it's nice because it makes all functions and operators defined for VectorExpression also available for MyVector. By using a simple base class VectorExpressionBase that only deals with storage and the [] operator, all other operators and methods don't need to be duplicated in the specialization for V = void.
Users would only need to know about classes MyVector<T,N> (for storing data) and possibly about VectorExpression<T,N,V> if they want to define additional functions and operators. VectorExpressionBase and the classes like VectorSum don't need to be visible to the outside world.
I find my original solution somewhat cleaner conceptually because the meaning of each class is more clear and because it doesn't require the template parameter V, but this one is more efficient because it doesn't require any virtual functions, which can probably make a large difference in certain cases.
Thanks for pointing me to the right links!
P.S. Surely most / all of this isn't new but I thought it would be nice to summarize and explain it a bit. I hope it can help others.
EDIT
I changed the type of data member VectorExpressionBase<T,N,V>::ref from V& to V. This is needed since the temporary V object the reference was pointing at may no longer exist at the time the VectorExpression is evaluated. For example, the temporary VectorSum object stops existing when the operator+ function returns, making the returned VectorExpression object useless.
I also completed the code with some constructors and corrected the operator+ function.

C++: Non-const operator taking preference over const overload

I have a class that represents a diagonal matrix. I only store the elements along the diagonal, so I don't waste space with a bunch of 0's. However, I still want to be able to use double brackets to access elements in the array. To get around that, I use an inner class, like this:
template <class T>
class DiagonalMatrix
{
private:
const T ZERO = 0;
int _size;
Vector<T> _data;
class row
{
private:
DiagonalMatrix<T>* _parent;
int _row;
public:
row(DiagonalMatrix<T>* parent, const int row)
: _parent(parent), _row(row) {}
T& operator[](const int i);
};
class const_row
{
private:
const DiagonalMatrix<T>* const _parent;
int _row;
public:
const_row(const DiagonalMatrix<T>* const parent, const int row)
: _parent(parent), _row(row) {}
const T& operator[](const int i) const;
};
friend class row;
friend class const_row;
public:
row operator[] (const int i);
const const_row operator[] (const int i) const;
// other stuff
};
And here are the relevant definitions:
template<class T>
typename DiagonalMatrix<T>::row DiagonalMatrix<T>::operator[](const int i)
{
if (i < 0 || i >= _size)
{
throw IndexOutOfBoundsException(i);
}
return DiagonalMatrix<T>::row(this, i);
}
template <class T>
T& DiagonalMatrix<T>::row::operator[](const int i)
{
if (i < 0 || i >= _parent->_size)
{
throw IndexOutOfBoundsException(i);
}
if (row == col)
{
return _parent->_data[row];
}
// TODO Add a real exception
throw "Cannot modify non-diagonal elements";
}
With similar definitions for the const versions, except the const operator[] returns a reference to the constant ZERO instead of throwing for non-diagonal elements.
So here is my problem: The non-const version is being called even when I don't need to modify anything. For example, this throws my error string:
DiagonalMatrix<double> diag(5);
// fill in the diagonal elements with some values
cout << diag[0][2] << endl;
However, if I remove the non-const versions of the operator, it behaves as expected and outputs a 0.
I've also tried something like:
T& at(const int row, const int col);
const T& at(const int row, const int col) const;
// in main:
cout << diag.at(0, 2) << endl;
But this has the same issue. So I have two questions:
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
It choose the non-const version because diag is not a const object.
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
You can define a const refrence to diag and use it to print values:
const DiagonalMatrix<double> &const_diag = diag;
cout << diag[0][2] << endl; // call const version
Or you define a function to print values and pass a const reference in:
void show_diag(const DiagonalMatrix<double> &diag)
{
cout << diag[0][2] << endl; // call const version
}
show_diag(diag);

A custom Vector and Matrix class in C++ and operator[]

I have a vector class in C++ that relies on raw pointer. I dont use std::vector as I need to create vector objects from raw pointers for specifal cases. Here is very simple example of my class:
template <typename T>
class Vector
{ ...
private:
T * m_data; int m_size; bool dontFree; ...
public:
Vector(T *const ptr, int size) { m_data = ptr; m_size = size; dontFree = true; }
Vector(int size, T val) { ... dontFree = false; }
~Vector(): { if(!dontFree) delete [] m_data; }
T& operator[](const size_type index);
};
Similarly I have the matrix data type that also stores data in raw pointer and can use vector to support [][] as it is not allowed in C++, something like:
template<typename T>
class Matrix
{
private:
T * m_data; ...
public:
...
Vector<T>& operator[](const int rowIndex)
{
return Vector<T>(&m_data[rowSize * rowIndex], rowSize);
}
}
How could I do efficiently implement operator[] for matrix returing a Vector so that I can write code, something follow:
Matrix<int> m(5,5);
m[1][1] = 10;
int temp = m[1][2];
Please suggest considering the overhead of copy constructor etc.
Create a proxy class that overloads operator[] that you can give access to your matrix's array. Something like this:
template<typename T>
class Proxy
{
public:
Proxy(T * tp)
:rowStart(tp)
{}
T & operator[](const int columnIndex)
{
return rowStart[columnIndex];
}
private:
T * rowStart;
};
Then your Matrix class' operator[] can return one of these, like this:
Proxy<T> operator[](const int rowIndex)
{
return Proxy<T>(m_data + rowSize * rowIndex);
}
It's not complete of course, but it should get you started.
You should return vector by value to make your code correct. Also you can write a small proxy if your vector does a lot of work inside a copy constructor.
If you implement your operator[] as inline method (e.g. don't move implementation to cpp) then good compiler should optimize your code and eliminate unnecessary copying.
But if you are crazy about performance then you can return a raw pointer from the operator:
...
T* operator[](const int rowIndex)
{
return m_data + rowSize * rowIndex;
}
...
int temp = m[1][2];
But is a dangerous approach!
The recommendation when implementing multidimensional matrices is not to overload operator[], but rather overload operator() with multiple dimensions. There are a few reasons that you can read in the C++ FAQ lite
template <typename T>
class Matrix {
public:
typedef std::size_t size_type;
typedef T & reference;
typedef T const & const_reference;
const_reference operator()( size_type x, size_type y ) const;
reference operator()( size_type x, size_type y );
};

templated code not working while non-templated code works!

I spent several hours, completely stuck when I realized that only the templated version of my code has a bug.
In the following code, when pushing_back elements in the myMap, the original vectors myVec1 and myVec2 are modified and contain garbage at the end of the execution. If I un-template everything, just replacing template<T> by double, then the code works fine as I would expect (the original arrays are untouched).
The funny thing is if I put a cout in the copy constructor, it does not get called if the code is templated. But it gets called if I replace the copy constructor with Vector<T2> by the original type Vector<T>, and then everything work fine.
Why wouldn't the compiler know that T2==T since I only use double?
(note, the code has been made as short as possible so as to show the errors - I thus removed accessors, made everything public etc.).
#include <vector>
#include <map>
template<class T>
class Vector{
public:
Vector():n(0),data(0){};
Vector(int N):n(N),data(new T[N]){};
Vector(T x, T y):n(2),data(new T[2]){data[0]=x; data[1]=y;};
template<class T2> Vector(const Vector<T2>& rhs):n(rhs.n), data(new T[n])
{
for (int i=0; i<n; i++)
data[i] = T(rhs.data[i]);
}
~Vector(){delete[] data;}
Vector& operator=(const Vector& rhs)
{
if (rhs.n != n)
{
if (data)
delete[] data;
data = new T[rhs.n];
}
n = rhs.n;
memcpy(data, rhs.data, n*sizeof(T));
return *this;
}
T& operator[](int i){return data[i];}
const T& operator[](int i) const {return data[i];}
int n;
T* data;
};
typedef Vector<double> Vectord;
template <class T> inline bool operator<(const Vector<T>& v1, const Vector<T>& v2)
{
for (int i=0; i<v1.n; i++)
{
if (v1[i]<v2[i]) return true;
if (v1[i]>v2[i]) return false;
}
return false;
}
int main(int argc, char** argv)
{
std::vector<Vectord> myVec1(3);
myVec1[0] = Vectord(1.,3.);
myVec1[1] = Vectord(3.,3.);
myVec1[2] = Vectord(1.,5.);
std::vector<Vectord> myVec2(3);
myVec2[0] = Vectord(4.,1.);
myVec2[1] = Vectord(2.,5.);
myVec2[2] = Vectord(6.,5.);
std::map<Vectord, std::vector<Vectord> > myMap;
for (int i=0; i<3; i++)
{
myMap[myVec1[i]].push_back(myVec2[i]);
}
return 0;
}
A templated constructor is never a copy constructor.
So your class is using the automatically generated copy constructor.
Cheers & hth.,