C++11 dynamically allocated variable length multidimensional array - c++

I've been trying to create a variable length multidimensional array. As I understand, you can't create variable length arrays on the stack, but you can create 1D variable length arrays in C++ using dynamic allocation. Correct me if this is a compiler extension, but it seems to work fine on clang and gcc with --pedantic set.
int size = 10;
int *ary = new int[size]();
I tried to extend the concept to multidimensional arrays. Here are my results. The problem with possiblity 1 and 2 is that they require a constexpr and do not work with variable sizes. Is it possible to make either of them accept a variable as its size? I put possibility 3 as I am aware of it, but it lacks [][] access, which is what I'm looking for.
constexpr int constSize = 10;
//Possibility 1: Only works in C++11
//Creates CONTIGUOUS 2D array equivalent to array[n*n], but with [][] access
int (*ary1)[constSize] = new int[constSize][constSize]();
delete [] ary1;
//Possibility 2:
//Really horrible as it does NOT create a contiguous 2D array
//Instead creates n seperate arrays that are each themselves contiguous
//Also requires a lot of deletes, quite messy
int **ary2 = new int*[constSize];
for (int i = 0; i < n; ++i)
ary2[i] = new int[constSize];
for (int i = 0; i < n; ++i)
delete [] ary2;
delete [] ary2;
//Possibility 3:
//This DOES work with non-constexpr variable
//However it does not offer [][] access, need to access element using ary[i*n+j]
int *ary3 = new int[size*size];
delete [] ary3;

This will create a dynamically allocated 2D variable-length array, with dimensions w and h:
std::vector<std::vector<int>> ary4(w, std::vector<int>(h));
It can be accessed with [][]:
ary4[x][y] = 0;
However, it's not contiguously allocated. To get a contiguous array, here's one solution:
template<typename E>
class Contiguous2DArray
{
public:
Contiguous2DArray(std::size_t width, std::size_t height)
: array(width * height), width(width) {}
E& operator()(std::size_t x, std::size_t y)
{ return array[x + width * y]; }
private:
std::vector<E> array;
std::size_t width;
}
It can be used like this:
Contiguous2DArray<int> ary5(w, h);
ary5(x, y) = 0;

The number of dimensions is fixed, because the type of what [] returns changes based on the number of dimensions. Access is through both repeated [] and (...). The first mimics C-style array lookup. The (...) syntax must be complete (it must pass N args to an N dimensional array). There is a modest efficiency cost to support both.
Uses C++14 features to save on verbosity. None are essential.
Using an an n_dim_array with 0 dimensions will give bad results.
template<class T, size_t N>
struct array_index {
size_t const* dimensions;
size_t offset;
T* buffer;
array_index<T,N-1> operator[](size_t i)&&{
return {dimensions+1, (offset+i)* *dimensions, buffer};
}
template<class...Is, std::enable_if_t<sizeof...(Is) == N>>
T& operator()(size_t i, Is...is)&&{
return std::move(*this)[i](is...);
}
};
template<class T>
struct array_index<T,0> {
size_t const* dimension;
size_t offset;
T* buffer;
T& operator[](size_t i)&&{
return buffer[i+offset];
}
T& operator()(size_t i)&&{
return std::move(*this)[i];
}
};
template<class T, size_t N>
struct n_dim_array {
template<class...Szs, class=std::enable_if_t<sizeof...(Szs)==N>>
explicit n_dim_array( Szs... sizes ):
szs{ { static_cast<size_t>(sizes)... } }
{
size_t sz = 1;
for( size_t s : szs )
sz *= s;
buffer.resize(sz);
}
n_dim_array( n_dim_array const& o ) = default;
n_dim_array& operator=( n_dim_array const& o ) = default;
using top_level_index = array_index<T,N-1>;
top_level_index index(){return {szs.data(),0,buffer.data()};}
auto operator[]( size_t i ) {
return index()[i];
}
using const_top_level_index = array_index<const T,N-1>;
const_top_level_index index()const{return {szs.data(),0,buffer.data()};}
auto operator[]( size_t i ) const {
return index()[i];
}
template<class...Is,class=std::enable_if_t<sizeof...(Is)==N>>
T& operator()(Is...is){
return index()(is...);
}
template<class...Is,class=std::enable_if_t<sizeof...(Is)==N>>
T const& operator()(Is...is) const {
return index()(is...);
}
private:
n_dim_array() = delete;
std::array<size_t,N> szs;
std::vector<T> buffer;
};
live example
Does not support for(:) loop iteration. Writing an iterator isn't that hard: I'd do it in array_index.

Related

How to declare 2D dynamic array in C++

How to declare a 2D array in which the rows are dynamic but the rows length are fixed? Is there any way to do it without both row and rows length are dynamic?
P.S. I can't use STL containers or class string.
You can use std::vector and std::array for this.
std::vector is a dynamic-length array.
std::array is a fixed-length array, used as
array<int, 20> arr;
arr[10] = 42;
array<int, 20> anotherArr = arr; // copied here, as opposed to C arrays
int oldStyleArr[20];
oldStyleArr[10] = 42;
// int newStyleArr[20] = oldStyleArr; // error here
It is a convenient wrapper over the C-style array, and it provides value semantics and various conveniece methods like size().
So you can create array<vector<int>, 20> for an array of 20 dynamic vectors of ints or vector<array<int, 20>> for a dynamic vector of fixed-length arrays.
UPD: std::array works only with array bounds known at compile-time. If your array bounds are known only at runtime, you still can use std::vector's constructor from size and (optional) element:
int rowCount, columnCount;
cin >> rowCount >> columnCount;
using Row = vector<int>;
// create `vector` of `rowCount` rows,
// where each row is `vector` of `columnCount` ints
vector<Row> arr2d(rowCount, Row(columnCount));
However, that's not the most efficient solution because each row is allocated separately. You can solve this with a little wrapper over one-dimensional vector:
template<class T>
class Vector2D {
public:
Vector2D(int rows, int cols)
: data(rows*cols)
, rows(rows)
, cols(cols) {}
int rowCount() const { return rows; }
int columnCount() const { return cols; }
T& get(int r, int c) { return data[r*cols + c]; }
T const& get(int r, int c) const { return data[r*cols + c]; }
void addRow() {
data.resize(cols*(rows + 1));
}
// ...
private:
vector<T> data;
int rows;
int cols;
};
You can use std::vector for dynamic range arrays. You would want to instantiate a vector of arrays to achieve this.
What you are looking for is probably: std::vector<std::array<int, 20>> arr;
However, if STL containers are not an option you might need to implement the container yourself. A linked list is probably the easiest to implement.
Just declare a 1D array and calculate the index yourself like how compilers generate accesses to a multidimensional array. Each row has width items, so the [x][y] element will have the index x*width + y
template<typename T>
class twoD
{
const int width;
const int height;
T* data;
twoD(int w, int h) : width(w), height(h)
{
data = new T[width*height];
}
~twoD()
{
delete[] data;
}
T& at(int x, int y)
{
return data[x*width + y];
}
T const& at(int x, int y) const
{
return data[x*width + y];
}
}
twoD myArray(4, 8);
myArray.at(2, 3) = 5;
myArray.at(4, 5) = 6 - myArray.at(2, 3);
The same method can be used to access multidimensional arrays in any degree

Storing std::vectors in google::dense_hash_map makes it slower

I need mapping from uint64->[list of uint64] (list length is constant per hash table).
I have tried using google::dense_hash_map in two ways:
1.google::dense_hash_map<uint64, std::array<uint64, 10>, Hash64> //10 for example
2.google::dense_hash_map<uint64, std::vector<uint64>, Hash64>
(1) works much faster (3-fold) than (2). The problem is, I don't want to define the size of array in compilation time but when defining the hash-map, is there another option possible?
Most of my operations are modifying the values in the hash-table, and I sometime erase all elements so I can use the same allocated memory.
You can try to employ some memory pooling to avoid dynamic allocations and get more compact (cache-friendly) memory usage. This is a very simple examplary solution that works for me together with boost::dense_hash_map:
template <typename T>
class pooled_rt_array {
public:
static void init_pool(size_t capacity) {
pool_.resize(capacity);
top_ = pool_.data();
}
pooled_rt_array() : data_(top_), size_(0) { }
pooled_rt_array(size_t size) : data_(top_), size_(size) {
assert(top_ + size <= pool_.data() + pool_.size()); // not safe, in fact
top_ += size;
}
T & operator[](size_t n) { return *(data_ + n); }
const T & operator[](size_t n) const { return *(data_ + n); }
size_t size() const { return size_; }
private:
T * data_;
size_t size_;
static std::vector<T> pool_;
static T * top_;
};
template <typename T>
std::vector<T> pooled_rt_array<T>::pool_;
template <typename T>
T * pooled_rt_array<T>::top_;
A simple usage:
int main() {
using value_t = pooled_rt_array<uint64_t>;
google::hash_dense_map<uint64_t, value_t
/* , std::hash<uint64_t>, std::equal_to<uint64_t> */
> m;
m.set_empty_key(0xFFFFFFFFFFFFFFFF);
size_t n;
std::cin >> n;
value_t::init_pool(1000000 * n); // pool for 1000000 arrays
value_t a(n);
for (size_t i = 0; i < a.size(); i++) a[i] = i;
m[0] = std::move(a);
}
I also did some benchmark and this was much faster than storing std::vector in the map.
If the size of arrays is the same for all of them, you can even remove the size_ member variable from pooled_rt_array, which will make its instances having the size of a single pointer.
Note that there are much more sophisticated ways how to employ memory pooling, such as those provided by Boost. You can for example use some special pool-aware allocators and use them with std::vector.

End of array points to newly allocated array C++

Using C++, I am trying to create an array that holds pointers to objects I'm storing. But when the array is full, I want to expand the array.
the easy option is to allocate a new array with bigger size, then copy the elements to it, this is quite inefficient, and I thought of another way I want to try to do it:
create array of fixed size X
When full, create a new array, and make the end of the first array point to the start of the first element
Repeat as long as needed
What methods can I use to do that? I thought of one way to do it, but it seems very hacky:
declare all my new array as pointers to object pointer, then reinterprit_cast the filled elements to object pointer.
Note: I know I can use Vector, but I am instructed not to use std library.
Kind Regards,
There are some good answers in the comments already. I just want to provide a way to achieve exactly the behavior you described.
Since the elements of the array are pointers as well, you can define a union as the element of your array like this:
template<typename T>
union Cell
{
T* pElm;
Cell* pNext;//A fixed size array of Cells
}
And then build your array on top of it. For example:
template<typename T>
class SpecialArray
{
public:
//the next pointer is included
static const size_t ARRAY_LEN = 1000;// For example
using Pointer = T*;
using Segment = Cell<T>[ARRAY_LEN];
protected:
Segment* pFirst;
size_t mSize;
public:
SpecialArray()
:pFirst(nullptr),mSize(0){}
SpecialArray(SpecialArray&&){}
~SpecialArray(){}
Pointer& operator[](size_t index)
{
Segment* seg = pFirst;
size_t offest = 0;
//Search logic...
return seg[offest]->pElm;
}
const Pointer& operator[](size_t index) const;
};
Using C++, I am trying to create an array that holds pointers to
objects I'm storing. But when the array is full, I want to expand the
array.
With C++ templates and C primitives we can improvise a simple vector like below. And the grow buffer strategy is to double the size when the threshold is met.
#include <iostream>
#include <stdlib.h>
template <typename T>
class MyVector
{
public:
MyVector() : m_count(0), m_size(0), m_buffer(0)
{
m_size = bufInitSize;
m_buffer = (T*)malloc(sizeof(T) * bufInitSize);
}
~MyVector()
{
if (m_buffer)
free(m_buffer);
}
void add(const T& p)
{
if (m_count + 1 >= m_size)
{
m_size *= 2;
m_buffer = (T*)realloc(m_buffer, sizeof(T) * m_size);
}
m_buffer[m_count ++ ] = p;
}
T& operator[](int idx)
{
return m_buffer[idx];
}
private:
static const int bufInitSize = 1024;
T* m_buffer;
int m_count;
int m_size;
};
void main()
{
// using MyVector
MyVector<int*> vctOfIntPtr;
int n = 100;
vctOfIntPtr.add(&n);
int* pN = vctOfIntPtr[0];
std::cout << *pN;
}

Return one dimension of an array?

How would I only return one dimension of an array, while ignoring the other?
Such as:
int map[4][8];
int MapManager::getMapX(int x)
{
return map[x];
}
The return type should be int* or int[], not int:
int* MapManager::getMapX(int x) {
return map[x];
}
Other than that, you are fine.
With a 2 dimensional array you will only be able to directly return a one dimensional array for the inner array by converting to a pointer, such as
int map[4][8];
int* MapManager::getMapX(int x)
{
return map[x];
}
For the other 'dimension', you will need to have another external array to copy to:
int* MapManager::getMapY(int y, int *outArray, int numElements)
{
for(int i = 0; i < numElements; i++) {
outArray[i] = map[i][y];
}
}
This array needs to be allocated with the correct size. (8 in this case).
The reason for this is that the array elements for the y 'column' are not contiguous in memory, but spread across several arrays (which are the 'x' rows). C arrays rely on this contiguous concept for accessing the elements.
Since none of the other answers here return an actual array (pointers are not arrays), I thought I might show how to really return an array. Or the closest thing possible, which is a reference to an array.
typedef int row_type[8];
row_type& MapManager::getMapX(int x) {
return map[x];
}
What's the point of this? The pointer works the same!
No, it doesn't. The pointer loses type information, namely, the size. You can make begin() and end() functions work with arrays, but you can't with pointers:
// pointer version
int* MapManager::getMapX_ptr(int x) {
return map[x];
}
row_type& row = getMapX(0);
// row is of type int(&)[8]
// notice the size is not lost in the type!
std::sort(begin(row), end(row));
// compiles fine! end() correctly finds the end of the row
int* ptr = getMapX_ptr(0);
// notice how ptr has no size information at all
std::sort(begin(ptr), end(ptr));
// can't possible be made to work!
You can't write end for int*.
template <typename T, std::size_t N>
T* end(T(&arr)[N]) {
return &arr[0] + N;
}
template <typename T>
T* end(T* ptr) {
// what here?
// guess?
// pick a random number?
}
You could create a special class that provides a strided view of an array. That is to say, it skips over values. Here's the beginnings of something like that:
template<typename T>
class StridedView
{
public:
StridedView(T * b, int stride, int count)
:begin_(b), stride_(stride), count_(count)
{}
template<int N>
StridedView(T (&arr)[N])
:begin_(arr), stride_(1), count_(N)
{}
T & operator[](int index)
{
return *(begin_ + index * stride_);
}
const T & operator[](int index) const
{
return *(begin_ + index * stride_);
}
int size() const { return count_; }
private:
T * begin_;
int stride_;
int count_;
};
Then you could have functions that can get you a row or a column as appropriate:
template<typename T, int R, int C>
StridedView<T> GetRow(T (&arr)[R][C], int row)
{
T * begin = (*arr) + (row * C);
return StridedView<T>(begin, 1, C);
}
template<typename T, int R, int C>
StridedView<T> GetColumn(T (&arr)[R][C], int column)
{
T * begin = (*arr) + column;
return StridedView<T>(begin, C, R);
}
Demo

allocating vectors (or vectors of vectors) dynamically

I need to dynamically allocate 1-D and 2-D arrays whose sizes are given at run-time.
I managed to "discover" std::vector and I think it fits my purposes, but I would like to ask whether what I've written is correct and/or can be improved.
This is what I'm doing:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
Dynamically allocating arrays is required when your dimensions are given at runtime, as you've discovered.
However, std::vector is already a wrapper around this process, so dynamically allocating vectors is like a double positive. It's redundant.
Just write (C++98):
#include <vector>
typedef std::vector< std::vector<double> > matrix;
matrix name(sizeX, std::vector<double>(sizeY));
or (C++11 and later):
#include <vector>
using matrix = std::vector<std::vector<double>>;
matrix name(sizeX, std::vector<double>(sizeY));
You're conflating two issues, dynamic allocation and resizable containers. You don't need to worry about dynamic allocation, since your container does that for you already, so just say it like this:
matrix name(sizeX, std::vector<double>(sizeY));
This will make name an object with automatic storage duration, and you can access its members via name[i][j].
What you're doing should basically work, however:
In general, don't dynamically allocate objects
If you want a vector, do this:
std::vector<double> vec(size);
not this:
std::vector<double>* vec = new std::vector<double>(size);
The latter gives you a pointer, which you have to delete. The former gives you a vector which, when it goes out of scope, cleans up after itself. (Internally, of course, it dynamically allocates objects, but the trick is that this is handled by the class itself, and you don't need to worry about it in your user code).
It is correct but could be made more efficient.
You could use the boost multidimensional arrays:
http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html
Or, you can implement your own class for it and handle the indexing yourself.
Perhaps something like this (which is not well tested):
#include <vector>
#include <cassert>
template <typename T, typename A = std::allocator<T> >
class Array2d
{
public:
typedef Array2d<T> self;
typedef std::vector<T, A> Storage;
typedef typename Storage::iterator iterator;
typedef typename Storage::const_iterator const_iterator;
Array2d() : major_(0), minor_(0) {}
Array2d(size_t major, size_t minor)
: major_(major)
, minor_(minor)
, storage_(major * minor)
{}
template <typename U>
Array2d(size_t major, size_t minor, U const& init)
: major_(major)
, minor_(minor)
, storage_(major * minor, u)
{
}
iterator begin() { return storage_.begin(); }
const_iterator begin() const { return storage_.begin(); }
iterator end() { return storage_.end(); }
const_iterator end() const { return storage_.end(); }
iterator begin(size_t major) {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
const_iterator begin(size_t major) const {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
iterator end(size_t major) {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
const_iterator end(size_t major) const {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
void clear() {
storage_.clear();
major_ = 0;
minor_ = 0;
}
void clearResize(size_t major, size_t minor)
{
clear();
storage_.resize(major * minor);
major_ = major;
minor_ = minor;
}
void resize(size_t major, size_t minor)
{
if ((major != major_) && (minor != minor_))
{
Array2d tmp(major, minor);
swap(tmp);
// Get minimum minor axis
size_t const dist = (tmp.minor_ < minor_) ? tmp.minor_ : minor_;
size_t m = 0;
// copy values across
for (; (m < tmp.major_) && (m < major_); ++m) {
std::copy(tmp.begin(m), tmp.begin(m) + dist, begin(m));
}
}
}
void swap(self& other)
{
storage_.swap(other.storage_);
std::swap(major_, other.major_);
std::swap(minor_, other.minor_);
}
size_t minor() const {
return minor_;
}
size_t major() const {
return major_;
}
T* buffer() { return &storage_[0]; }
T const* buffer() const { return &storage_[0]; }
bool empty() const {
return storage_.empty();
}
template <typename ArrRef, typename Ref>
class MajorProxy
{
ArrRef arr_;
size_t major_;
public:
MajorProxy(ArrRef arr, size_t major)
: arr_(arr)
, major_(major)
{}
Ref operator[](size_t index) const {
assert(index < arr_.minor());
return *(arr_.buffer() + (index + (major_ * arr_.minor())));
}
};
MajorProxy<self&, T&>
operator[](size_t major) {
return MajorProxy<self&, T&>(*this, major);
}
MajorProxy<self const&, T const&>
operator[](size_t major) const {
return MajorProxy<self&, T&>(*this, major);
}
private:
size_t major_;
size_t minor_;
Storage storage_;
};
While the points the other answers made were very correct (don't dynamically allocate the vector via new, but rather let the vector do the allocation), if you are thinking terms of vectors and matrices (e.g. linear algebra), you might want to consider using the Eigen matrix library.
You don't allocate containers dynamically. They can automatically manage memory for you if they themselves are not manually managed.
A vector grows when you add new items with push_back (or insert), you can choose its size from the start with arguments to the constructor, and you can resize it later with the resize method.
Creating a vector of vectors with your sizes with the constructor looks like this:
std::vector< std::vector<double> > matrix(size, std::vector<double>(sizeY));
This means: size instances of a std::vector<double>, each containing sizeY doubles (initialized to 0.0).
Sometimes you don't want to fill your stack and your memory requirement is large. Hence you may want to use vector> created dynamically especially while creating a table of a given row and col values.
Here is my take on this in C++11
int main() {
int row, col;
std::cin >> row >> col;
auto *arr = new std::vector<std::vector<int>*>(row);
for (int i=0; i<row; i++) {
auto *x = new std::vector<int>(col, 5);
(*arr)[i] = x;
}
for (int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
std::cout << arr->at(i)->at(j) << " ";
}
std::cout << std::endl;
}
return 0;
}
#include < iostream >
#include < vector >
using namespace std;
int main(){
vector<int>*v = new vector<int>(); // for 1d vector just copy paste it
v->push_back(5);
v->push_back(10);
v->push_back(20);
v->push_back(25);
for(int i=0;i<v->size();i++){
cout<<v->at(i)<<" ";
}
cout<<endl;
delete v;
system("pause");
return 0;
}
If you don't need to resize the array sizes at run time, then you can just use standard arrays (allocated at runtime)!
However, if you do need to resize arrays at runtime, then you can use the following (revised) code:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
In essence, all I've done is remove a single bracket (().