Initializing a ublas vector from a C array - c++

I am writing a Matlab extension using the C++ ublas library, and I would like to be able to initialize my ublas vectors from the C arrays passed by the Matlab interpeter.
How can I initialize the ublas vector from a C array without (for the sake of efficiency) explicitly copying the data. I am looking for something along the following lines of code:
using namespace boost::numeric::ublas;
int pv[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
vector<int> v (pv);
In general, is it possible to initialize a C++ std::vector from an array? Something like this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int pv[4] = { 4, 4, 4, 4};
vector<int> v (pv, pv+4);
pv[0] = 0;
cout << "v[0]=" << v[0] << " " << "pv[0]=" << pv[0] << endl;
return 0;
}
but where the initialization would not copy the data. In this case the output is
v[0]=4 pv[0]=0
but I want the output to be the same, where updating the C array changes the data pointed to by the C++ vector
v[0]=0 pv[0]=0

I'm not sure how your question relates to MATLAB/MEX, but a side note, you might want to know that MATLAB implements a copy-on-write strategy.
This means that when you copy an array for example, only some headers are actually copied, while the data itself is shared between the two arrays. And once one of them is modified, a copy of the data is actually made.
The following is a simluation of what might be happening under the hood (borrowed from this old post):
-----------------------------------------
>> a = [35.7 100.2 1.2e7];
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink=0
-----------------------------------------
>> b = a;
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink / \
| / \ |
| | |
| | |
\ / | |
crosslink |
mxArray b |
pdata --------
-----------------------------------------
>> a(1) = 1;
mxArray a
pdata -----> (1) 100.2 1.2e7
crosslink=0
crosslink=0
mxArray b
pdata ------> 35.7 100.2 1.2e7 ...
I know this doesn't really answer your question, I just thought you might find the concept helpful.

Both std::vector and ublas::vector are containers. The whole point of containers is to manage the storage and lifetimes of their contained objects. This is why when you initialize them they must copy values into storage that they own.
C arrays are areas of memory fixed in size and location so by their nature you can only get their values into a container by copying.
You can use C arrays as the input to many algorithm functions so perhaps you can do that to avoid the initial copy?

You can initialize a std::vector from a C array easily:
vector<int> v(pv, pv+10);

There are two undocumented classes in uBLAS storage.hpp. You can change the default storage class (unbounded_array) in ublas::vector with one of these.
The first class, array_adaptor, makes a copy of your data when ublas::vector calls to copy constructor, not very useful class at all. I would rather simply the appropriate constructor to do this in unbounded_array or bounded_array classes.
The second, shallow_array_adaptor, only hold a reference of your data, so you can use vector to directly modify your C array. Unfortunately, it has some bugs, when you assign an expression it losses the original data pointer. But you can create a derived class that fix this problem.
Here the patch and an example:
// BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR must be defined before include vector.hpp
#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR
#include <boost/numeric/ublas/vector.hpp>
#include <algorithm>
#include <iostream>
// Derived class that fix base class bug. Same name, different namespace.
template<typename T>
class shallow_array_adaptor
: public boost::numeric::ublas::shallow_array_adaptor<T>
{
public:
typedef boost::numeric::ublas::shallow_array_adaptor<T> base_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::pointer pointer;
shallow_array_adaptor(size_type n) : base_type(n) {}
shallow_array_adaptor(size_type n, pointer data) : base_type(n,data) {}
shallow_array_adaptor(const shallow_array_adaptor& c) : base_type(c) {}
// This function must swap the values ​​of the items, not the data pointers.
void swap(shallow_array_adaptor& a) {
if (base_type::begin() != a.begin())
std::swap_ranges(base_type::begin(), base_type::end(), a.begin());
}
};
void test() {
using namespace boost::numeric;
typedef ublas::vector<double,shallow_array_adaptor<double> > vector_adaptor;
struct point {
double x;
double y;
double z;
};
point p = { 1, 2, 3 };
vector_adaptor v(shallow_array_adaptor<double>(3, &p.x));
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
v += v*2.0;
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
}
Output:
1 2 3
3 6 9

The usual suggestion to use shallow array adaptor seems kind of sarcastic to me - to be able to simply access an array through a pointer you're supposed to put it into a shared_array with all the reference counting shebang (that comes to nothing, since you don't own the array) and what's more with a nightmare of data-aliasing.
Actually, uBLAS has a fully-fledged implementation of storage (array_adaptor) which allows to use vectors with external c arrays. The only catch is vector constructor which makes a copy. Why this nice feature is not used in the library is quite beyond me, but anyway, we can use a little extension (it's actually 2 lines of code surrounded with usual c++ bloat)
template<class T>
class extarray_vector :
public vector<T, array_adaptor<T> >
{
typedef vector<T, array_adaptor<T> > vector_type;
public:
BOOST_UBLAS_INLINE
extarray_vector(size_type size, pointer p)
{ data().resize(size, p); }
template <size_type N>
BOOST_UBLAS_INLINE
extarray_vector(T (&a)[N])
{ data().resize(N, a); }
template<class V>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector<T, V>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VC>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_container<VC>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VE>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_expression<VE>& ae)
{
vector_type::operator = (ae);
return *this;
}
};
you can use it like this:
int i[] = {1, 4, 9, 16, 25, 36, 49};
extarray_vector<int> iv(i);
BOOST_ASSERT_MSG(i == &iv[0], "Vector should attach to external array\n");
iv[3] = 100;
BOOST_ASSERT(i[3] == 100);
iv.resize(iv.size() + 1, true);
BOOST_ASSERT_MSG(i != &iv[0], "And detach from the array on resize\n");
iv[3] = 200;
BOOST_ASSERT(i[3] == 100);
iv.data().resize(7, i, 0);
BOOST_ASSERT_MSG(i == &iv[0], "And attach back to the array\n");
BOOST_ASSERT(i[3] == 200);
You can dynamically attach and detach vector to external storage via array_adaptor's resize method (keeping or discarding data). On resize it detaches from storage automatically and becomes regular vector. Assignment from containers goes directly into storage, but assignment from expression is done via a temporary and vector is detached from storage, use noalias() to prevent that. There's a small overhead in constructor since data_ is private member and we have to default initialize it with new T[0], then reassign to external array. You may change it to protected and assign to storage directly in the constructor.

Here are a couple of functions for syntactically convenient assignment (admittedly not initialization):
vector<int> v;
setVector(v, 3,
1, 2, 3);
matrix<int> m;
setMatrix(m, 3, 4,
1, 2, 3, 4,
11, 22, 33, 44,
111, 222, 333, 444);
The functions:
/**
* Resize a ublas vector and set its elements
*/
template <class T> void setVector(vector<T> &v, int n, ...)
{
va_list ap;
va_start(ap, n);
v.resize(n);
for (int i = 0; i < n; i++) {
v[i] = va_arg(ap, T);
}
va_end(ap);
}
/**
* Resize a ublas matrix and set its elements
*/
template <class T> void setMatrix(matrix<T> &m, int rows, int cols ...)
{
va_list ap;
va_start(ap, cols);
m.resize(rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m(i, j) = va_arg(ap, T);
}
}
va_end(ap);
}

Related

use of algorithms in function cause ERROR: no instance of overloaded function

I'm trying to use an algorithm in a function.
Should be very simple.
However, regardless of which algorithm I attempt to use, all of them cause the same error when used in a function.
E0304 no instance of overloaded function "std::begin" matches the argument list
E0304 no instance of overloaded function "std::end" matches the argument list
I am guessing there is some small change that needs to be made.
#include <iostream>
#include <algorithm>
#include "bool_element_option_03.h"
#include "storage.h"
int main()
{
int arr_value[ELEMENTS]{ 1, 2, 9, 4, 5, 6, 7, 8 };
int arr_copy_value[ELEMENTS];
// array population
for (int var_create_array_a = 0; var_create_array_a < ELEMENTS; var_create_array_a++)
{
arr_copy_value[var_create_array_a] = 0;
}
//std::copy(std::begin(arr_value), std::end(arr_value), std::begin(arr_copy_value));
//std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
for (int output = 0; output < ELEMENTS; output++)
{
std::cout << "copied decimals: " << arr_copy_value[output] << std::endl;
}
bool_element_option_03(arr_value, arr_copy_value);
return 0;
}
#ifndef _STORAGE_H
#define _STORAGE_H
#define WIN32_LEAN_AND_MEAN
// -----------------------------------------------------------------------------------------------------------------------------------------------------
// Constants
// -----------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------
const int ELEMENTS = 8;
//-----------------------------------------------
#endif
#include <iostream>
#include <algorithm>
#include "storage.h"
void bool_element_option_03(int arr_value[], int* arr_copy_value)
{
std::copy(std::begin(arr_value + ELEMENTS), std::end(arr_value + ELEMENTS), std::begin(arr_copy_value + ELEMENTS));
std::sort(std::rbegin(arr_copy_value + ELEMENTS), std::rend(arr_copy_value + ELEMENTS));
for (int output = 0; output < ELEMENTS; output++)
{
std::cout << "copied decimals: " << arr_copy_value[output] << std::endl;
}
}
If I take these algorithms out of the function and put them in main(), they work as they should.
Should I intentionally overload this function (so I can use algorithms in it)?
Overloading this function is not my intention.
I'm not calling it multiple times with different arguments.
This function is only being called once.
The error text is explicit:
E0304 no instance of overloaded function "std::begin" matches the argument list
So, what are those instances? See e.g. https://en.cppreference.com/w/cpp/iterator/begin
template< class C >
constexpr auto begin( C& c ) -> decltype(c.begin());
template< class C >
constexpr auto begin( const C& c ) -> decltype(c.begin());
Returns exactly c.begin(), which is typically an iterator to the beginning of the sequence represented by c. If C is a standard Container, this returns C::iterator when c is not const-qualified, and C::const_iterator otherwise.
template< class T, std::size_t N >
constexpr T* begin( T (&array)[N] ) noexcept;
Returns a pointer to the beginning of the array.
The last one seems promising, its argument is a reference to an array (note how it's declared) and that is the overload used here:
int main()
{
int arr_value[ELEMENTS]{ 1, 2, 9, 4, 5, 6, 7, 8 };
int arr_copy_value[ELEMENTS];
// ...
std::copy(std::begin(arr_value), // <---
std::end(arr_value),
std::begin(arr_copy_value)); // <---
// ...
}
That's because both arr_value and arr_copy_value are arrays, there.
When the compiler reads the refactored code, on the other end, it can't find a suitable overload:
void bool_element_option_03(int arr_value[], int* arr_copy_value)
{ // ^^ That's kind of misleading
std::copy(std::begin(arr_value + ELEMENTS),
std::end(arr_value + ELEMENTS),
std::begin(arr_copy_value + ELEMENTS));
// ...
}
Here, both arr_value and arr_copy_values are pointers, not arrays and there's no overload of std::begin() (and the likes) accepting a pointer in the Standard Library.
Given the call bool_element_option_03(arr_value, arr_copy_value); in main and due to array to pointer decay(1), they point to the respective first elements of the two arrays declared in main. They are local variables which happen to have the same name of the variables in main.
Besides, arr_value + ELEMENTS points one after the last element of the array. It's a valid pointer as long as it's not dereferenced.
You can make this function works, without changing the call site, by directly passing those pointers(2) to the SL algorithm functions:
void bool_element_option_03(int const *arr_value, int *arr_copy_value)
{
std::copy(arr_value, arr_value + ELEMENTS, arr_copy_value);
std::sort(arr_copy_value, arr_copy_value + ELEMENTS, std::greater{});
// ...
}
This can be generalized by passing the size too:
void bool_element_option_03( size_t n, int const *src, int *dest)
{ // ^^^^^^^^
std::copy(src, src + n, dest);
std::sort(dest, dest + n, std::greater{});
// ...
}
To generalize a bit more, you can modify the function signature into a template accepting references of array:
template< class Type, std::size_t N>
void bool_element_option_03(Type const (&arr_value)[N], Type (&arr_copy_value)[N])
{
std::copy(std::begin(arr_value), std::end(arr_value),
std::begin(arr_copy_value));
std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
// ...
}
Which can still be called in main with bool_element_option_03(arr_value, arr_copy_value);, except that, now, there's no decay and the arrays are actually passed by reference and the correct overload of std::begin can be selected.
To mimic the Standard Library algorithms, we can instead pass iterators directly:
template< class SourceRandomIterator, class DestRandomIterator >
void copy_and_sort( SourceRandomIterator source_first
, SourceRandomIterator source_last
, DestRandomIterator dest_first )
{
auto dest_last{ std::copy(source_first, source_last, dest_first) };
std::sort(dest_first, dest_last, std::greater{});
// ...
}
But we also have to modify the call in main:
bool_element_option_03(std::cbegin(arr_value), std::cend(arr_value),
std::begin(arr_copy_value));
Since C++20, we can use std::span as arguments.
void bool_element_option_03(std::span<const int> arr_value,
std::span<int> arr_copy_value)
{
std::copy(std::begin(arr_value), std::end(arr_value),
std::begin(arr_copy_value));
std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
// ...
}
Or take advantage of the ranges library:
template< std::ranges::random_access_range SourceRange
, std::ranges::random_access_range DestRange >
void bool_element_option_03(SourceRange const& source,
DestRange& dest)
{
std::ranges::copy(source, dest);
std::ranges::sort(dest | std::ranges::views::reverse );
// ...
}
In both cases, this function can be called from main as bool_element_option_03(arr_value, arr_copy_value);
1) What is array to pointer decay?
2) See e.g. How are iterators and pointers related? and how std::sort is declared.
thanks for your help everyone!
this is what I decide to go with.
#include <iostream>
#include <algorithm>
constexpr size_t ELEMENTS{ 8 };
void show(const int(&arr)[ELEMENTS])
{
for (const auto& c : arr)
std::cout << c;
std::cout << '\n';
}
void bool_element_option_03(const int(&arr_value)[ELEMENTS], int(&arr_copy_value)[ELEMENTS])
{
std::copy(std::begin(arr_value), std::end(arr_value), std::begin(arr_copy_value));
std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
std::cout << "\nReverse sorted:\n";
show(arr_copy_value);
}
int main()
{
const int arr_value[ELEMENTS]{ 1, 2, 9, 4, 5, 6, 7, 8 };
int arr_copy_value[ELEMENTS]{};
std::cout << "\nOriginal order:\n";
show(arr_value);
bool_element_option_03(arr_value, arr_copy_value);
}

Sorting the Addressess of the pointers in a dynamically allocated array of class

I've created a dynamically allocated array of a class.
class AlienShip
{
public:
int DAMAGE;
..........
};
AlienShip * ships = new AlienShip[N];
Where N is between 2 and 50 inclusively. After initialization of each element, I want to sort the array in the decreasing value of DAMAGE in each of ships.
I implemented a simple bubble sort to do the same. However, instead of moving whole objects around, I want to move the addresses of pointers. I did something like this:
....
if(ships[j].DAMAGE < ships[j+1].DAMAGE)
swap( ships + j, ships + j + 1)
....
But it shows a compile-time error, saying it didn't find any matching function swap. I think the swap() is defined as a template in <cstdlib> then why does it not work?
EDIT: I discovered that sorting the pointer address does NOT necessarily sorts the array. 😅 But I wrote a swap function to sort some pointer address but it didn't have any effect.
mySwap(int* a, int* b){
int *tmp;
tmp = a, a = b, b = tmp;
}
I wanted to swap the address of a and b. So that *b refers to previous *a. But it didn't work. I wonder why?
Since you have an array of AlienShips, and you want to sort on the DAMAGE variable of each, then use std::sort with a custom comparison function. You don't need to sort pointers. You have one pointer (to the start of your array). Using that pointers, you get each AlienShip.
If you want to swap a pair of AlienShips, you can take advantage of the fact that you should have a default assignment operator for your class.
swap(AlienShip& a, AlienShip& b) {
AlienShip temp = a;
a = b;
b = temp;
}
But instead of having a pointer to dynamically acquired memory using new, you should either statically allocate memory (using std::array) or dynamically allocate memory (using std::vector). Then you can use std::sort in <algorithm> to easily sort your array.
Example follows:
#include <algorithm> // for std::sort
#include <functional> // for std::greater
#include <array> // for std::array
#include <iostream> // for std::cout and std::ostream
#include <vector> // for std::vector
constexpr int num_alien_ships = 10;
class AlienShip
{
public:
AlienShip(int damage)
: damage_(damage)
{}
inline const int& damage() const {
return damage_;
}
private:
int damage_;
};
// This operator<< overload is provided for convenience in showing that
// the ships are actually sorted below
std::ostream& operator<<(std::ostream& os, const AlienShip& alien_ship) {
os << alien_ship.damage();
return os;
}
// If you define a greater-than operator for your AlienShips,
// then you can use the std::greater template from <algorithm>
// to sort from big damage to small damage
bool operator>(const AlienShip& a, const AlienShip& b) {
return a.damage() > b.damage();
}
int main() {
std::array<AlienShip, num_alien_ships> alien_array = { 1, 9, 2, 8, 3, 7, 4, 6, 5, 0 };
std::sort(alien_array.begin(), alien_array.end(),
[](const AlienShip& a, const AlienShip& b) { return a.damage() > b.damage(); }
);
std::cout << "Result of sorting alien_array using a custom lambda:\n";
for (const AlienShip& a : alien_array) {
std::cout << a << ' ';
}
std::cout << '\n';
std::cout << "Result of sorting alien_vector using std::greater:\n";
std::vector<AlienShip> alien_vector = { 8, 6, 7, 5, 3, 0, 9 };
std::sort(alien_vector.begin(), alien_vector.end(), std::greater<AlienShip>());
for (const AlienShip& a : alien_vector) {
std::cout << a << ' ';
}
std::cout << '\n';
}
Use the overloaded operator> function to define ordering for your AlienShips if it makes sense for them to be sorted by damage_. If that order only makes sense in the context of this single sort operation, stick to the lambda.
If you really want to sort by moving around pointers, them you need an actual array of pointers:
AlienShip* alien_ship_ptr[10];
std::for_each(std::begin(alien_ship_ptr), std::end(alien_ship_ptr), [](AlienShip*& asp){ asp = new AlienShip; });
After populating your array of pointers, then you can sort them using the methods described above.
You can only swap variables. ships + j is not a variable reference.
ships have AlienShip type and j probably is int in your case,
try this swap(ships[j],ships[j+1])

Pass array through class constructor using C++ variadic templates

I would like to modernize a small mathematical library using new C++ paradigms (I have a C++17 compiler). In specific, I need to pass an array to a class through constructor.
This is the "classical" old way I used. It works
class Vector {
public:
long double* elements;
public:
Vector(int size, long double *array) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(10, array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
So, I tried to change Vector class with what I have understood about variadic templates and parameter pack. It doesn't work
class Vector {
public:
long double* elements;
public:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{args...};
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
The error returned by compiler is
error: cannot convert ‘long double*’ to ‘long double’ in initialization
elements = new long double[size]{args...};
What am I doing wrong?
Further, I'm wondering if it is possible to use a std::array instead of raw array, both either inside main method and in Vector class.
To pass an array like that variadic templates are not the solution. Variadic templates are used to pass N numbers of parameters to a class/function. Yet you are passing only one parameter!
I would suggest you to
I suggest you tu use array references, which are available in all C++ versions:
class Vector {
public:
long double* elements;
public:
template<std::size_t size>
Vector(long double (&array)[size]) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
By the way, if you can, use vector. I highly doubt this custom vector class is as efficient as std::vector (no geometric growth or optimized copy and move)
I'm not sure if this answers your question, but I would give you a general advice:
I guess you want to encapsulate your own logic into the vector.
The standard library vector is very advanced and you should use it, instead of loosing time to write your own low-level code. You could concentrate more on the logic you need.
Your could define your own vector and still use the advantages of the std::vector for constructing your Vector objects.
For example with inheritance:
template<typename T>
class Vector : public std::vector<int>
{
// here comes the implementation of your interface.
}
or composition:
template<typename T>
class Vector {
private:
std::vector<T> elems;
}
In the case of composition you'd have to define the constructors you need.
In both cases you could then use your own Vector as follows:
Vector<double> vec1(10); // construct vector with 10 double's each = 0
Vector<double> vec2(10, 5); // construct vector with 10 double's each = 5
Vector<double> vec3{1,2,3,4}; // using initializer list
Vector<double> vec4(somecontainer.begin(), somecontainer.end()); // construct vector by copying elemts from some other container
etc.
As you see with std::vector you'are getting all the benefits you need for constructing your own Vector object.
According to your definition of
template<typename... Args> Vector(Args... args);
You want to use this constructor in this way:
Vector vector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
It is possible, if you sightly modify your definition of the constructor to:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{static_cast<long double>(args)...};
}
Please note such kind of use is not good practice, you should normally use std containers and avoid new operator.

Array of a specific size used out of the function it was initialized in

I'm a high school student learning programming and I have a problem that I can't figure out how to solve.
I have an integer "x", and I want a matrix "mat" to have the size of "x":
int mat[x][x];
But that works only in main() where I've read x;
For example if x == 5, the equivalent would be
int mat[5][5];
#include <iostream>
using namespace std;
int x;
int mat[x][x];
void f(int mat2[x][x])
{
}
int main()
{
cin >> x;
int m[x][x];
f(m);
}
I've wrote this short program to show where it works and it doesn't work.
error: array bound is not an integer constant before ']' token
I've the error at the global declaration, at the declaration in function void f. It only compiles without errors in main();
What can I do to create a matrix with the size of x outside of the main function?
Variable length arrays aren't spported in standard c++. Besides you don't want the global definition.
What you can use portably in that case is std::vector:
void f(std::vector<std::vector<int>>& mat)
{
}
int main()
{
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
f(m);
}
If you pass that vector around to functions or being allocated within functions, the size information will be kept at any time.
What can I do to create a matrix with the size of x outside of the main function?
Something like this:
std::vector<std::vector<int>> foo() {
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
return m;
}
int main()
{
std::vector<std::vector<int>> mat = foo();
}
Handling of multi-dimension arrays in C++ is not easy. The best way to go is often to map a multi-dimensionnal indexing with a linear memory chunk.
For instance, for a 2 by 2 matrix, one can create an array of 2*2=4 elements and map it this way:
+-----------+-----------+-----------+-----------+
| map[0][0] | map[0][1] | map[1][0] | map[1][1] |
+-----------+-----------+-----------+-----------+
This seems overly complicated at first glance, but it simplifies greatly the memory allocation.
For an arbitrary sized matrix of width by height, map[i][j] is at index i*height + j. This can be translated in C++, encapsulated in a template class Matrix:
#include <array>
template <typename T, size_t WIDTH, size_t HEIGHT>
class Matrix {
std::array<T, WIDTH*HEIGHT> data;
public:
T& operator()(size_t i, size_t j) {
return data[i*HEIGHT + j];
}
const T& operator()(size_t i, size_t j) const {
return data[i*HEIGHT + j];
}
};
This has the disadvantage that the Matrix' dimensions must be known at compile time (and can be mitigated, see note (ii) at end of answer). But it makes its use so easy:
void fill(Matrix<int, 2, 2>& m) {
m(0,0) = 0;
m(0,1) = 1;
m(1,0) = 2;
m(1,1) = 3;
}
int main() {
Matrix<int, 2, 2> m;
fill(m);
std::cout << m(1,0) << "\n";
}
Note (i): Elements are indexed by (line, column) rather than [line][column] because we can't create an operator[] accepting multiple values.
Live on coliru
Note (ii): This basic idea can be enriched (demo) to handle resizable matrixes, with use of a std::vector instead of std::array and a proxy to std::vector::resize().
Variable-length array is supported by some compiler as an extension. The manual of the compiler provides more information.Gnu VLR
The storage duration of a variable-length array(if supported) generally can't be static, which is why you get the error message (global variables have static storage duration).
Unrelated: The major array bound of the parameter mat2 isn't necessary, i.e. void f(int mat2[x][x]) is equivalent to void f(int mat2[][x]).
C++ has no provision for dynamic 2D matrix but provides all you need to create complex classes. A (static) 2D array is a contiguously allocated array of height arrays of width elements. Just mimic that and:
allocate a linear array of width * height
provide an operator[](int) that returns a pointer to the first element of ith row
do necessary housekeeping in destructor and in a copy (and move if C++11 or above) constructor.
Example of code:
template <typename T>
class Matrix {
T *data;
int width;
int height;
public:
// direct ctor
Matrix(int h, int w): width(w), height(h) {
data = new T[w * h];
}
//copy ctor
Matrix(const Matrix& src): width(src.width), height(src.height) {
data = new T[width * height]; // allocate and copy data array
for (int i=0; i<width * height; i++) data[i] = src.data[i];
}
// move ctor
Matrix(Matrix&& src): width(src.width), height(src.height) {
data = src.data; // steal original array in a move
src.data = NULL; // ensure no deletion will occur at src destruction
}
~Matrix() {
delete data;
data = NULL;
}
// explicitely delete assignement operators
Matrix& operator = (const Matrix&) = delete;
Matrix& operator = (Matrix&&) = delete;
T* operator[](int i) {
//optionaly test 0 <= i < width
return &data[i * width];
}
};
int main()
{
int w;
std::cin >> x;
Matrix<int> m(x, x);
// you can then use m[i][j] as you would for a static 2D array
...
}
This class does not support any resizing by design. If you need that, you really should use a vector<vector<T> >. The downside is that it has no default ctor either, because the dimension must be given at definition time (even if we could easily imagine a 2 phases initialization...).
You can dynamic allocate memory to use, in the c/c++, it does not support dynamic size of static memory allocation, so, you just modify your code like this.
int x;
cin >>x;
int** mat = new int[x][x];

int[n][m], where n and m are known at runtime

I often need to create a 2D array with width and height (let them be n and m) unknown at compile time, usually I write :
vector<int> arr(n * m);
And I access elements manually with :
arr[j * m + i]
I recently got told that I could instead write :
int arr[n][m] // n and m still only known at runtime.
So here are 2 questions :
Is this behaviour allowed by the C++ Standard ?
How should I pass such an array to a function ? g++ reports that arr has type int (*)[n], but again, n is dynamic and not known outside the function where it is declared (main).
The feature you are asking about (where the dimensions are only made known at runtime) is a non-standard extension of C++, but a standard one of C.99 (made into an optional feature in C.11). The feature is called variable-length array (VLA), and the link is the documentation for GCC.
If you are using GCC, then you are to pass the length of the array as a parameter to the function.
void foo (int m, int arr[][m]) {
//...
}
However, there seems to be a bug in either the compiler or the documentation, as the above function prototype syntax only works when compiling C code, not C++ (as of gcc version 4.8.2). The only work-around I found was to use a void * parameter, and cast it int the function body:
int foo_workaround (int m, void *x)
{
int (*arr)[m] = static_cast<int (*)[m]>(x);
//...
}
There are other solutions if you do not want to rely on a compiler extension. If you don't mind a separate allocation for each row, you can use a vector of vectors, for example:
std::vector<std::vector<int> > arr(n, std::vector<int>(m));
However, if you want a single allocation block like you demonstrated in your own example, then it is better to create a wrapper class around vector to give you 2-d like syntax.
template <typename T>
class vector2d {
int n_;
int m_;
std::vector<T> vec_;
template <typename I>
class vector2d_ref {
typedef std::iterator_traits<I> TRAITS;
typedef typename TRAITS::value_type R_TYPE;
template <typename> friend class vector2d;
I p_;
vector2d_ref (I p) : p_(p) {}
public:
R_TYPE & operator [] (int j) { return *(p_+j); }
};
typedef std::vector<T> VEC;
typedef vector2d_ref<typename VEC::iterator> REF;
typedef vector2d_ref<typename VEC::const_iterator> CREF;
template <typename I>
vector2d_ref<I> ref (I p, int i) { return p + (i * m_); }
public:
vector2d (int n, int m) : n_(n), m_(m), vec_(n*m) {}
REF operator [] (int i) { return ref(vec_.begin(), i); }
CREF operator [] (int i) const { return ref(vec_.begin(), i); }
};
The wrapper's operator[] returns an intermediate object that also overloads operator[] to allow 2-dimensional array syntax when using the wrapper.
vector2d<int> v(n, m);
v[i][j] = 7;
std::cout << v[i][j] << '\n';
Why not have an std::vector of std::vector's?
std::vector<std::vector<int> > arr(n, std::vector<int>(m));
Accessing an item then becomes:
std::cout << "(2,1) = " << arr[2][1] << std::endl;
A std::vector of std::vector's (from #include <vector>) would do the same thing as a 2-Dimensional array:
int n = 10, m = 10; //vector dimensions
std::vector<std::vector<int>> arr(n, std::vector<int>(m)); //Create 2D vector (vector will be stored as "std::vector<int> arr(n * m);
//you can get values from 2D vector the same way that you can for arrays
int a = 5, b = 5, value = 12345;
arr[a][b] = 12345;
std::cout << "The element at position (" << a << ", " << b << ") is " << arr[a][b] << "." << std::endl;
outputs:
The element at position (5, 5) is 12345.