Related
Background: this is a followup to #pari's answer to Constant-sized vector.
My type, metadata_t does not have a default constructor.
I use std::make_unique for fixed-size arrays that the size is not available in compile-time. (ie const size).
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
// note: this is run-time:
auto n = array.size();
return fixedsize_side_metadata_t(array.begin(), array.end()); // error
return fixedsize_side_metadata_t(array); // error
return std::unique_ptr<metadata_t[]>(0); // no error, but not useful
return std::unique_ptr<metadata_t[]>(n); // error
}
However, the constructor of unique_ptr<...[]> only accepts a size (integer). How do I initialise and copy my vector into my unique_ptr<[]>?
I tried std::unique_ptr<metadata_t[]>(array.size()); to prepare and then copy/populate the contents in the next step, but it shows a compile error.
Note: I use C++20 (or higher if it was available). Could make_unique_for_overwrite be useful? ( C++23 ).
Note: At first I thought generate (as in this answer) can do it, but it does not solve my problem because n is a run-time information.
The size of my vector is determined at run-time.
The whole point of this function is to convert my std::vector into a fixed-size data structure (with run-time size).
The data structure does not have to be unique_ptr<T[]>.
The old title referred to unique_ptr but I am really looking for a solution for a fixed-size data structure. So far, it is the only data structure I found as a "constant-size indexed container with size defined at runtime".
You can't initialize the elements of a unique_ptr<T[]> array with the elements of a vector<T> array when constructing the new array (UPDATE: apparently you can, but it is still not going to be a solution solved with a single statement, as you are trying to do).
You will have to allocate the T[] array first, and then copy the vector's elements into that array one at a time, eg:
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
fixedsize_metadata_t result = std::make_unique<metadata_t[]>(array.size());
std::copy(array.begin(), array.end(), result.get());
return result;
}
UPDATE: you updated your question to say that metadata_t does not have a default constructor. Well, that greatly complicates your situation.
The only way to create an array of objects that don't support default construction is to allocate an array of raw bytes of sufficient size and then use placement-new to construct the individual objects within those bytes. But now, you are having to manage not only the objects in the array, but also the byte array itself. By itself, unique_ptr<T[]> won't be able to free that byte array, so you would have to provide it with a custom deleter that frees the objects and the byte array. Which also means, you will have to keep track of how many objects are in the array (something new[] does for you so delete[] works, but you can't access that counter, so you will need your own), eg:
struct metadata_arr_deleter
{
void operator()(metadata_t *arr){
size_t count = *(reinterpret_cast<size_t*>(arr)-1);
for (size_t i = 0; i < count; ++i) {
arr[i]->~metadata_t();
}
delete[] reinterpret_cast<char*>(arr);
}
};
typedef std::unique_ptr<metadata_t[], metadata_arr_deleter> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
const auto n = array.size();
const size_t element_size = sizeof(std::aligned_storage_t<sizeof(metadata_t), alignof(metadata_t)>);
auto raw_bytes = std::make_unique<char[]>(sizeof(size_t) + (n * element_size));
size_t *ptr = reinterpret_cast<size_t*>(raw_bytes.get());
*ptr++ = n;
auto *uarr = reinterpret_cast<metadata_t*>(ptr);
size_t i = 0;
try {
for (i = 0; i < n; ++i) {
new (&uarr[i]) metadata_t(array[i]);
}
}
catch (...) {
for (size_t j = 0; j < i; ++j) {
uarr[j]->~metadata_t();
}
throw;
}
raw_bytes.release();
return fixedsize_metadata_t(uarr);
}
Needless to say, this puts much more responsibility on you to allocate and free memory correctly, and it is really just not worth the effort at this point. std::vector already supports everything you need. It can create an object array using a size known at runtime, and it can create non-default-constructable objects in that array, eg.
std::vector<metadata_t> consolidate(const std::vector<metadata_t> &array) {
auto n = array.size();
std::vector<metadata_t> varr;
varr.reserve(n);
for (const auto &elem : array) {
// either:
varr.push_back(elem);
// or:
varr.emplace_back(elem);
// it doesn't really matter in this case, since they
// will both copy-construct the new element in the array
// from the current element being iterated...
}
return varr;
}
Which is really just a less-efficient way of avoiding the vector's own copy constructor:
std::vector<metadata_t> consolidate(const std::vector<metadata_t> &array) {
return array; // will return a new copy of the array
}
The data structure does not have to be unique_ptr<T[]>. The old title referred to unique_ptr but I am really looking for a solution for a fixed-size data structure. So far, it is the only data structure I found as a "constant-size indexed container with size defined at runtime".
What you are looking for is exactly what std::vector already gives you. You just don't seem to realize it, or want to accept it. Both std::unique_ptr<T[]> and std::vector<T> hold a pointer to a dynamically-allocated array of a fixed size specified at runtime. It is just that std::vector offers more functionality than std::unique_ptr<T[]> does to manage that array (for instance, re-allocating the array to a different size). You don't have to use that extra functionality if you don't need it, but its base functionality will suit your needs just fine.
Initializing an array of non-default constructibles from a vector is tricky.
One way, if you know that your vector will never contain more than a certain amount of elements, could be to create an index_sequence covering all elements in the vector. There will be one instantiation of the template for each number of elements in your vector that you plan to support and the compilation time will be "silly".
Here I've selected the limit 512. It must have a limit, or else the compiler will spin in endless recursion until it gives up or crashes.
namespace detail {
template <class T, size_t... I>
auto helper(const std::vector<T>& v, std::index_sequence<I...>) {
if constexpr (sizeof...(I) > 512) { // max 512 elements in the vector.
return std::unique_ptr<T[]>{}; // return empty unique_ptr or throw
} else {
// some shortcuts to limit the depth of the call stack
if(sizeof...(I)+255 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+256>{});
if(sizeof...(I)+127 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+128>{});
if(sizeof...(I)+63 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+64>{});
if(sizeof...(I)+31 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+32>{});
if(sizeof...(I)+15 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+16>{});
if(sizeof...(I)+7 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+8>{});
if(sizeof...(I)+3 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+4>{});
if(sizeof...(I)+1 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+2>{});
if(sizeof...(I) < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+1>{});
// sizeof...(I) == v.size(), create the pointer:
return std::unique_ptr<T[]>(new T[sizeof...(I)]{v[I]...});
}
}
} // namespace detail
template <class T>
auto make_unique_from_vector(const std::vector<T>& v) {
return detail::helper(v, std::make_index_sequence<0>{});
}
You can then turn your vector into a std::unique_ptr<metadata_t[]>:
auto up = make_unique_from_vector(foos);
if(up) {
// all is good
}
Demo (compilation time may exceed the time limit)
You have to allocate some uninitialized memory for an array and copy construct the elements in-place using construct_at. You can then create a unique_ptr using the address of the constructed array:
#include <vector>
#include <memory>
struct metadata_t {
metadata_t(int) { }
};
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
// note: this is run-time:
auto n = array.size();
std::allocator<metadata_t> alloc;
metadata_t *t = alloc.allocate(n);
for (std::size_t i = 0; i < array.size(); ++i) {
std::construct_at(&t[i], array[i]);
}
return fixedsize_metadata_t(t);
}
I am mostly a C programmer, and I am looking for a fast and elegant solution to do what I want in C++. Let us consider this simple data structure
struct mystruct
{
int * array1;
int * array2;
size_t size;
};
The two pointers array1 and array2 are to be thought as two arrays of length size. I need a huge amount of these (about 2**30 or 1.000.000.000) all of the same small size (about 100). All of them will be deallocated at the exact same time. I can do the following in C with only one call to malloc where K is the number of struct I need and N is the size of the arrays
EDITED VERSION (see the old one below)
size_t NN = N * sizeof(int);
struct mystruct * my_objects = malloc(K * sizeof(struct mystruct));
int * memory = malloc(2*K*NN);
for(i=0; i<K; ++i)
{
my_objects[i].size = N;
my_objects[i].array1 = memory + 2*i*NN;
my_objects[i].array2 = memory + (2*i+1)*NN;
}
...
free(my_objects);
free(memory);
This version does not support very huge K and does not allow me to resize the array. But it is not so hard to design something for that purpose. Is there a way of creating a class in C++ that would be a kind of std::vector<mystruct> with forbidden shrinking and for which the allocation of array1 and array2 would not be based on dynamical allocation for each entry? I do want to minimize the effect of memory allocation since K is very big.
OLD VERSION:
size_t KK = K * sizeof(mystruct);
size_t NN = N * sizeof(int);
struct mystruct * my_objects = (struct mystruct *) malloc(KK + 2*K*NN);
for(i=0; i<K; ++i)
{
my_objects[i].size = N;
my_objects[i].array1 = (int *) (my_objects + KK + 2*i*NN);
my_objects[i].array2 = (int *) (my_objects + KK + (2*i+1)*NN);
}
Here's my literal translation from C to C++ that maintains the same memory layout:
std::unique_ptr<int[]> const memory(new int[2 * K * N]);
std::vector<mystruct> my_objects;
my_objects.reserve(K);
for (int i = 0; i < K; ++i)
{
mystruct const tmp = {N, memory + 2*i*NN, memory + (2*i+1)*NN};
my_objects.push_back(tmp);
}
The following does two memory allocations, one for each vector. Naturally you have to ensure that the ints vector lives longer than mystructs vector, since mystructs's members refer to ints's members.
struct mystruct
{
int* array1;
int* array2;
std::size_t size;
};
std::vector<int> ints(N*2*K);
std::vector<mystruct> mystructs(K);
for (std::size_t i=0; i<K; i++) {
mystruct& ms = mystructs[i];
ms.array1 = &ints[2*N*i];
ms.array2 = &ints[2*N*i+1];
ms.size = N;
}
Update:
As tp1 pointed out, std::vector might reseat its internal array, invalidating all pointers into it. If you never add or remove elements, that is not an issue. If you do, consider using std::deque instead for ints. However then you also have more memory allocations upon construction, see What really is a deque in STL?. Note that sadly C++ does not allow a const std::vector of non-const elements, see Const vector of non-const objects.
Note: Solution created with minimal manual memory handling in mind, before OP edited in that his main requirement was performance due to a very large K. As std::vector still does behind-the-scenes memory allocations, this isn't a fast solution, just an elegant one.
Might be improved with a custom memory allocator, but I think #Simple's answer is better all-around, especially if encapsuled in a wrapper class.
struct MyStruct
{
std::vector< int > array1;
std::vector< int > array2;
std::size_t size;
MyStruct( std::size_t init_size ) :
array1( std::vector< int >( init_size ) ),
array2( std::vector< int >( init_size ) ),
size( init_size )
{}
};
// ...
std::vector< MyStruct > my_objects( K, N );
No dynamic memory allocation at all. (Well, not by you, anyway.)
What you are doing here in C is that allocating an array externally to your struct, and than pointing pointers to the different parts of this array.
You can do exactly the same thing with std::vector<> - have a huge vector defined outside of your struct, and point pointers to different parts of this vector. Same thing exactly.
If N and K are known at compile time, but can be different in different places, then a template will work:
template <int N, int K>
struct Memory {
Memory() {
for (int i=0; i < K; i++) {
mystruct[i].array1 = data1[i];
mystruct[i].array2 = data2[i];
size[i] = N;
}
}
struct mystruct {
int * array1;
int * array2;
size_t size;
} mystructs[K];
int data1[K][N];
int data2[K][N];
};
void f() {
// The constructor sets up all the pointers.
Memory *m<100,200> = new Memory<100,200>();
.....
}
(I've not checked if that compiles.)
If the values are not known then I would not attempt to do this in one allocation; it makes more sense to do two allocations, one for an array of mystruct, and one for the integers. The extra overhead is minimal, and the code is much more maintainable.
struct Memory {
Memory(int N, int K) {
mystructs = new mystruct[K];
data = new int[2*K*N];
for (int i=0; i < K; i++) {
array1[i] = &data1[2*i*N];
array2[i] = &data2[(2*i+1)*N];
size[i] = N;
}
}
struct mystruct {
int * array1;
int * array2;
size_t size;
} mystruct *mystructs;
int *data;
};
(Again, I've not checked that compiles.)
Note that where your code has 2*i*N*sizeof(int) you have a bug because C pointer arithmetic does not count bytes; it counts multiples of the pointer type. In my code I've made this explicit by taking the address of an array item, but the maths is the same.
What you're trying to do can be done using the exact same code in c++.
However, it is utterly inadvisable in c++. The reason c++ has Object-Oriented semantics is to avoid the very situation you're reckoning with. Here's how I would handle this:
struct mystruct {
vector<int> array1;
vector<int> array2;
mystruct(size_t size);
}
mystruct::mystruct(size_t size) {
array1.resize(size);
array2.resize(size);
}
int main() {
vector<mystruct> mystructarray(numOfStructs, numOfElementsOfArray1AndArray2);
//EDIT: You don't need to expressly call the mystruct constructor, it'll be implicitly called with the variable passed into the vector constructor.
//Do whatever
return 0;
}
vector objects can be queried for their size at runtime, so there's no need to store size as a field of mystruct. And since you can define constructors for structs, it's best to handle creation of the object in that way. Finally, with a valid constructor, you can initialize an array of mystruct with a vector, passing in a valid argument for mystruct's constructor to build the vector.
DOUBLE EDIT COMBO: Alright, let's try a different approach.
Based on what you indicated in your comments, it sounds like you need to allocate a LOT of memory. I'm thinking this data has specific meaning in your application, which means it doesn't make a lot of sense to use generic data structures for your data. So here's what I'm proposing:
class mydata {
private:
size_t num_of_sets;
size_t size_of_arrays;
std::vector<int> data;
public:
mydata(size_t _sets, size_t _arrays)
: data(_sets * _arrays * 2),
num_of_sets(_sets),
size_of_arrays(_arrays) {}
int * const array1(size_t);
int * const array2(size_t);
};
int * const mydata::array1(size_t index)
{
return &(data[index*size_of_arrays * 2]);
}
int * const mydata::array2(size_t index)
{
return &(data[index*size_of_arrays * 2 + size_of_arrays]);
}
int main(int argc, char** argv) {
mydata data(16'777'216, 10);
data.array1(5)[5] = 7;
data.array2(7)[2] = 8;
std::cout << "Value of index 5's array1 at index 5: " << data.array1(5)[5] << std::endl;
std::cout << "Value of index 7's array2 at index 2: " << data.array2(7)[2] << std::endl;
//Do Something
return 0;
}
I have come across some code which allocates a 2d array with following approach:
auto a = new int[10][10];
Is this a valid thing to do in C++? I have search through several C++ reference books, none of them has mentioned such approach.
Normally I would have done the allocation manually as follow:
int **a = new int *[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
If the first approach is valid, then which one is preferred?
The first example:
auto a = new int[10][10];
That allocates a multidimensional array or array of arrays as a contiguous block of memory.
The second example:
int** a = new int*[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
That is not a true multidimensional array. It is, in fact, an array of pointers and requires two indirections to access each element.
The expression new int[10][10] means to allocate an array of ten elements of type int[10], so yes, it is a valid thing to do.
The type of the pointer returned by new is int(*)[10]; one could declare a variable of such a type via int (*ptr)[10];.
For the sake of legibility, one probably shouldn't use that syntax, and should prefer to use auto as in your example, or use a typedef to simplify as in
using int10 = int[10]; // typedef int int10[10];
int10 *ptr;
In this case, for small arrays, it is more efficient to allocate them on the stack. Perhaps even using a convenience wrapper such as std::array<std::array<int, 10>, 10>. However, in general, it is valid to do something like the following:
auto arr = new int[a][b];
Where a is a std::size_t and b is a constexpr std::size_t. This results in more efficient allocation as there should only be one call to operator new[] with sizeof(int) * a * b as the argument, instead of the a calls to operator new[] with sizeof(int) * b as the argument. As stated by Galik in his answer, there is also the potential for faster access times, due to increased cache coherency (the entire array is contiguous in memory).
However, the only reason I can imagine one using something like this would be with a compile-time-sized matrix/tensor, where all of the dimensions are known at compile time, but it allocates on the heap if it exceeds the stack size.
In general, it is probably best to write your own RAII wrapper class like follows (you would also need to add various accessors for height/width, along with implementing a copy/move constructor and assignment, but the general idea is here:
template <typename T>
class Matrix {
public:
Matrix( std::size_t height, std::size_t width ) : m_height( height ), m_width( width )
{
m_data = new T[height * width]();
}
~Matrix() { delete m_data; m_data = nullptr; }
public:
T& operator()( std::size_t x, std::size_t y )
{
// Add bounds-checking here depending on your use-case
// by throwing a std::out_of_range if x/y are outside
// of the valid domain.
return m_data[x + y * m_width];
}
const T& operator()( std::size_t x, std::size_t y ) const
{
return m_data[x + y * m_width];
}
private:
std::size_t m_height;
std::size_t m_width;
T* m_data;
};
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am working with a list of array in C++, each in an object and wanted to split some of them.
These are allocated dynamically.
I wanted to do the split in constant time as it is theoretically possible:
from
[ pointer, size1 ]
to
[ pointer, size2 ]; [ other array ]; [ pointer + size2, size1-size2 ]
(+ other data each time)
I tried to use malloc and simply create a new pointer incremented with the size.
As it could be expected, I got error due to the automatic freeing of the memory.
I tried a realloc starting at the second address, but as in "what is the difference between malloc and calloc" on this site already told me it is not possible.
Is there a way to avoid recopying the second part and define correctly the pointer?
Having a linear cost where I know I can have constant time is frustrating.
class TableA
{
public:
(constructor)
void divide(int size); // the one i am trying to implement
(other, geteur, seteur)
private
Evenement* _el;
vector<bool>** _old;//said arrays
int _size;
}
nothing really complicated
Basically, the malloc library can't cope with mallocing a chunk of memory and then freeing it slices.
You can do what you want, but you must only free the memory all at once right at the end using the original pointer that malloc handed you.
e.g.
int* p = malloc(9 * sizeof(int));
int* q = p + 3;
int* r = p + 6;
// Now we have three pointers to three arrays of three integers.
// Do stuff with p, q, r
free(p); // p is the only pointer it is valid to free.
By the way, if this is really about C++, there are probably standard C++ data structures you can use.
I don't think you can have only part of a dynamic array freed by keeping track of pointers and length. However, you can fake this by making a new class to manage the starting array, allocate it however you want and have it managed by a std::shared_ptr.
You simply return a Class containing a shared_ptr to memory, plain pointer to first element, and array size. When the current Array class goes out of scope, the shared_ptr gets decremented, and when no slices of the memory are used anymore, the memory gets freed.
You need to be careful with this though, as there may be multiple objects referencing the same memory, but there's ways around that (marking the original invalid after splitting with a bool for example).
[Edit] Below is a very basic implementation of this idea. A split() operator can very easily be implemented in terms of 2 slice() operations. I'm not sure how you want to implement this in terms of your example above, as I'm not sure how you manage your vector<bool> **, but if you wanted the possibility of splitting your vector<bool>, you could instantiate a ShareVector<bool>, or if you have an array of vector<bool>, your make a SharedVector<vector<bool>> instead.
#ifndef __SharedVector__
#define __SharedVector__
#include <memory>
#include <assert.h>
template <typename T>
class SharedVector {
std::shared_ptr<T> _data;
T *_begin;
size_t _size;
// perhaps add size_t capacity if need for limited resizing arises.
public:
SharedVector<T>(size_t const size)
: _data(std::shared_ptr<T>(new T[size], []( T *p ) { delete[] p; })), _begin(_data.get()), _size(size)
{}
// standard copy and move constructors work fine
// pass shared_ptr by reference to avoid unnecessary refcount changes
SharedVector<T>(std::shared_ptr<T> &data, T *begin, size_t size)
: _data(data), _begin(begin), _size(size)
{}
T& operator[] (const size_t nIndex) {
assert(nIndex < _size);
return _begin[nIndex];
}
T const & operator[] (const size_t nIndex) const {
assert(nIndex < _size);
return _begin.get()[nIndex];
}
size_t size(){
return _size;
}
SharedVector<T> slice(size_t const begin, size_t const end) {
assert(begin + end < _size);
return SharedVector<T>(_data, _begin + begin, end - begin);
}
T *begin() {
return _begin;
}
T *end() {
return _begin + _size;
}
};
#endif
I think the malloc and create new pointer idea is good. But you need to free the memory manually I think.
Maybe you can use std::copy.
int* p = (int*)malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++)
p[i] = i;
for (int i = 0; i < 5; i++)
std::cout << p[i];
// tmp will hold 3 values
// p2 will hold 2 values
// so we want to copy first 3 into tmp
// and last 2 into p2
int tmp[3];
std::copy(p, p+3, tmp);
for (int i = 0; i < 3; i++)
std::cout << tmp[i];
int p2[2];
std::copy(p+3, p+5, p2);
for (int i = 0; i < 2; i++)
std::cout << p2[i];
// get rid of original when done
free(p);
Output:
0123401234
The question is relatively unclear
But according to your topic
splitting dynamically allocated array without linear time copy
i would suggest you to use linked list instead of an array, you don't need to copy anything (and therefore no need to free anything UNLESS you wanna delete one of the item), manipulating the pointers would be sufficient for splitting a linked list
as in the title is it possible to join a number of arrays together without copying and only using pointers? I'm spending a significant amount of computation time copying smaller arrays into larger ones.
note I can't used vectors since umfpack (some matrix solving library) does not allow me to or i don't know how.
As an example:
int n = 5;
// dynamically allocate array with use of pointer
int *a = new int[n];
// define array pointed by *a as [1 2 3 4 5]
for(int i=0;i<n;i++) {
a[i]=i+1;
}
// pointer to array of pointers ??? --> this does not work
int *large_a = new int[4];
for(int i=0;i<4;i++) {
large_a[i] = a;
}
Note: There is already a simple solution I know and that is just to iteratively copy them to a new large array, but would be nice to know if there is no need to copy repeated blocks that are stored throughout the duration of the program. I'm in a learning curve atm.
thanks for reading everyone
as in the title is it possible to join a number of arrays together without copying and only using pointers?
In short, no.
A pointer is simply an address into memory - like a street address. You can't move two houses next to each other, just by copying their addresses around. Nor can you move two houses together by changing their addresses. Changing the address doesn't move the house, it points to a new house.
note I can't used vectors since umfpack (some matrix solving library) does not allow me to or i don't know how.
In most cases, you can pass the address of the first element of a std::vector when an array is expected.
std::vector a = {0, 1, 2}; // C++0x initialization
void c_fn_call(int*);
c_fn_call(&a[0]);
This works because vector guarantees that the storage for its contents is always contiguous.
However, when you insert or erase an element from a vector, it invalidates pointers and iterators that came from it. Any pointers you might have gotten from taking an element's address no longer point to the vector, if the storage that it has allocated must change size.
No. The memory of two arrays are not necessarily contiguous so there is no way to join them without copying. And array elements must be in contiguous memory...or pointer access would not be possible.
I'd probably use memcpy/memmove, which is still going to be copying the memory around, but at least it's been optimized and tested by your compiler vendor.
Of course, the "real" C++ way of doing it would be to use standard containers and iterators. If you've got memory scattered all over the place like this, it sounds like a better idea to me to use a linked list, unless you are going to do a lot of random access operations.
Also, keep in mind that if you use pointers and dynamically allocated arrays instead of standard containers, it's a lot easier to cause memory leaks and other problems. I know sometimes you don't have a choice, but just saying.
If you want to join arrays without copying the elements and at the same time you want to access the elements using subscript operator i.e [], then that isn't possible without writing a class which encapsulates all such functionalities.
I wrote the following class with minimal consideration, but it demonstrates the basic idea, which you can further edit if you want it to have functionalities which it's not currently having. There should be few error also, which I didn't write, just to make it look shorter, but I believe you will understand the code, and handle error cases accordingly.
template<typename T>
class joinable_array
{
std::vector<T*> m_data;
std::vector<size_t> m_size;
size_t m_allsize;
public:
joinable_array() : m_allsize() { }
joinable_array(T *a, size_t len) : m_allsize() { join(a,len);}
void join(T *a, size_t len)
{
m_data.push_back(a);
m_size.push_back(len);
m_allsize += len;
}
T & operator[](size_t i)
{
index ix = get_index(i);
return m_data[ix.v][ix.i];
}
const T & operator[](size_t i) const
{
index ix = get_index(i);
return m_data[ix.v][ix.i];
}
size_t size() const { return m_allsize; }
private:
struct index
{
size_t v;
size_t i;
};
index get_index(size_t i) const
{
index ix = { 0, i};
for(auto it = m_size.begin(); it != m_size.end(); it++)
{
if ( ix.i >= *it ) { ix.i -= *it; ix.v++; }
else break;
}
return ix;
}
};
And here is one test code:
#define alen(a) sizeof(a)/sizeof(*a)
int main() {
int a[] = {1,2,3,4,5,6};
int b[] = {11,12,13,14,15,16,17,18};
joinable_array<int> arr(a,alen(a));
arr.join(b, alen(b));
arr.join(a, alen(a)); //join it again!
for(size_t i = 0 ; i < arr.size() ; i++ )
std::cout << arr[i] << " ";
}
Output:
1 2 3 4 5 6 11 12 13 14 15 16 17 18 1 2 3 4 5 6
Online demo : http://ideone.com/VRSJI
Here's how to do it properly:
template<class T, class K1, class K2>
class JoinArray {
JoinArray(K1 &k1, K2 &k2) : k1(k1), k2(k2) { }
T operator[](int i) const { int s = k1.size(); if (i < s) return k1.operator[](i); else return k2.operator[](i-s); }
int size() const { return k1.size() + k2.size(); }
private:
K1 &k1;
K2 &k2;
};
template<class T, class K1, class K2>
JoinArray<T,K1,K2> join(K1 &k1, K2 &k2) { return JoinArray<T,K1,K2>(k1,k2); }
template<class T>
class NativeArray
{
NativeArray(T *ptr, int size) : ptr(ptr), size(size) { }
T operator[](int i) const { return ptr[i]; }
int size() const { return size; }
private:
T *ptr;
int size;
};
int main() {
int array[2] = { 0,1 };
int array2[2] = { 2,3 };
NativeArray<int> na(array, 2);
NativeArray<int> na2(array2, 2);
auto joinarray = join(na,na2);
}
A variable that is a pointer to a pointer must be declared as such.
This is done by placing an additional asterik in front of its name.
Hence, int **large_a = new int*[4]; Your large_a goes and find a pointer, while you've defined it as a pointer to an int. It should be defined (declared) as a pointer to a pointer variable. Just as int **large_a; could be enough.