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.
Related
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
I have a program in which the object array's size is determined during the runtime, so it's dynamically allocated (2D array, read from file). I also have a function which takes these objects as parameters. The problem is if the function parameters are 2D arrays that are passed to the function the 2nd dimension should be determined. However, in my case it is not. My program won't compile since the prototype does not have the 2nd dimension mentioned.
Here is what I tried:
//global variables
int residentCount=0;
int hospitalCount=0;
Resident** residents;
Hospital** hospitals;
bool readFromFiles(const string, const string, const int); //sizes are determined in here
void print(Hospital*[hospitalCount], Resident*[residentCount]); //declaration issue
How can I solve this?
You are programming in C++, so you should:
avoid dynamic allocation and handling memory management on your own always when it's possible
take advantage of objects with automatic storage duration instead, follow RAII idiom
avoid using C-style arrays and actually avoid writing C code that is just compilable as C++ in general
use great features that C++ provides, especially those bundled within STL
avoid using global variables when local equivalents suffice
This is how it could look like:
typedef std::vector<Resident> Residents;
typedef std::vector<Hospital> Hospitals;
// passing by const reference:
void print(const std::vector<Hospitals>&, const std::vector<Residents>&);
int main()
{
std::vector<Hospitals> hospitals;
std::vector<Residents> residents;
...
} // <-- lifetime of automatics declared within main ends here
Note that hospitals and residents will be objects with automatic storage duration, usable in similar manner than your C-style 2D arrays. When the execution goes out of the scope of main, these vectors are destructed and memory, where their elements (including elements of their elements) resided before is automatically cleaned up.
Also note that I suggest you to pass by const reference, i.e. const std::vector<Hospitals>&, which prevents the copy of passed object being created and const keyword explicitely tells to the caller: "Although you pass this object by reference, I will not change it."
Just pass a pointer to the first element of the array and the dimensions, that's enough, example:
void PrintHospitals(Hospital* Hospitals, size_t HospitalRows, size_t HospitalColumns)
{
size_t i, j;
Hospital* hospital;
for (i = 0; i < HospitalRows; i++)
for (j = 0; j < HospitalColumns; j++)
{
hospital = Hospitals + HospitalColumns * i + j;
PrintHospital(hospital);
}
}
int main()
{
Hospital hospitals[10][20];
// ...
PrintHospitals(&hospitals[0][0], 10, 20);
return 0;
}
Here is a solution using templates to create two-dimensional array wrappers for existing data:
template<typename T>
class Array2d {
public:
int Rows;
int Cols;
T** Data;
Array2d(int rows, int cols, T** data) :
Rows(rows),
Cols(cols),
Data(data) { }
};
void print(Array2d<Hospital> h, Array2d<Resident> r) {
for (int i = 0; i < h.Rows; i++) {
for (int j = 0; j < h.Cols; j++) {
//Print Data[i][j] element here
}
}
// Other print code
}
int main()
{
Resident** residents;
Hospital** hospitals;
//Init data arrays
Array2d<Hospital> h(10, 10, hospitals);
Array2d<Resident> r(10, 10, residents);
print(h, r);
}
I have an array of edges, which is defined as a C-style array of doubles, where every 4 doubles define an edge, like this:
double *p = ...;
printf("edge1: %lf %lf %lf %lf\n", p[0], p[1], p[2], p[3]);
printf("edge2: %lf %lf %lf %lf\n", p[4], p[5], p[6], p[7]);
So I want to use std::sort() to sort it by edge length. If it was a struct Edge { double x1, y1, x2, y2; }; Edge *p;, I would be good to go.
But in this case, the double array has a block size that is not expressed by the pointer type. qsort() allows you to explicitly specify the block size, but std::sort() infers the block-size by the pointer type.
For performance reasons (both memory-usage and CPU), let's say that it's undesirable to create new arrays, or transform the array somehow. For performance reasons again, let's say that we do want to use std::sort() instead of qsort().
Is it possible to call std::sort() without wasting a single CPU cycle on transforming the data?
Possible approach:
An obvious approach is to try to force-cast the pointer:
double *p = ...;
struct Edge { double arr[4]; };
Edge *p2 = reinterpret_cast<Edge*>(p);
std::sort(...);
But how do I make sure the data is aligned properly? Also, how do I make sure it will always be aligned properly on all platforms and architectures?
Or can I use a typedef double[4] Edge;?
How about having a reordering vector? You initialize vector with 1..N/L, pass std::sort a comparator that compares elements i1*L..i1*L+L to i2*L..i2*L+L, and when your vector is properly sorted, reorder the C array according to new order.
In response to comment: yes things get complicated, but it may just be good complication! Take a look here.
You can use a "stride iterator" for this. A "stride iterator" wraps another iterator and an integer step size. Here's a simple sketch:
template<typename Iter>
class stride_iterator
{
...
stride_iterator(Iter it, difference_type step = difference_type(1))
: it_(it), step_(step) {}
stride_iterator& operator++() {
std::advance(it_,step_);
return *this;
}
Iter base() const { return it_; }
difference_type step() const { return step_; }
...
private:
Iter it_;
difference_type step_;
};
Also, helper functions like these
template<typename Iter>
stride_iterator<Iter> make_stride_iter(
Iter it,
typename iterator_traits<Iter>::difference_type step)
{
return stride_iterator<Iter>(it,step);
}
template<typename Iter>
stride_iterator<Iter> make_stride_iter(
stride_iterator<Iter> it,
typename iterator_traits<Iter>::difference_type step)
{
return stride_iterator<Iter>(it.base(),it.step() * step);
}
should make it fairly easy to use stride iterators:
int array[N*L];
std::sort( make_stride_iter(array,L),
make_stride_iter(array,L)+N );
Implementing the iterator adapter all by yourself (with all operators) is probably not a good idea. As Matthieu pointed out, you can safe yourself a lot of typing if you make use of Boost's iterator adapter tools, for example.
Edit:
I just realized that this doesn't do what you wanted since std::sort will only exchange the first element of each block. I don't think there's an easy and portable solution for this. The problem I see is that swapping "elements" (your blocks) cannot be (easily) customized when using std::sort. You could possibly write your iterator to return a special reference type with a special swap function but I'm not sure whether the C++ standard guarantees that std::sort will use a swap function that is looked up via ADL. Your implementation may restrict it to std::swap.
I guess the best answer is still: "Just use qsort".
For the new question, we need to pass in sort() a kind of iterator that will not only let us compare the right things (i.e. will make sure to take 4 steps through our double[] each time instead of 1) but also swap the right things (i.e. swap 4 doubles instead of one).
We can accomplish both by simply reinterpreting our double array as if it were an array of 4 doubles. Doing this:
typedef double Edge[4];
doesn't work, since you can't assign an array, and swap will need to. But doing this:
typedef std::array<double, 4> Edge;
or, if not C++11:
struct Edge {
double vals[4];
};
satisfies both requirements. Thus:
void sort(double* begin, double* end) {
typedef std::array<double, 4> Edge;
Edge* edge_begin = reinterpret_cast<Edge*>(begin);
Edge* edge_end = reinterpret_cast<Edge*>(end);
std::sort(edge_begin, edge_end, compare_edges);
}
bool compare_edges(const Edge& lhs, const Edge& rhs) {
// to be implemented
}
If you're concerned about alignment, can always just assert that there's no extra padding:
static_assert(sizeof(Edge) == 4 * sizeof(double), "uh oh");
I don't remember exactly how to do this, but if you can fake anonymous functions, then you can make a comp(L) function that returns the version of comp for arrays of length L... that way L becomes a parameter, not a global, and you can use qsort. As others mentioned, except in the case where your array is already sorted, or backwards or something, qsort is going to be pretty much just as fast as any other algorithm. (there's a reason it's called quicksort after all...)
It's not part of any ANSI, ISO, or POSIX standard, but some systems provide the qsort_r() function, which allows you to pass an extra context parameter to the comparison function. You can then do something like this:
int comp(void *thunk, const void *a, const void *b)
{
int L = (int)thunk;
// compare a and b as you would normally with a qsort comparison function
}
qsort_r(array, N, sizeof(int) * L, (void *)L, comp);
Alternatively, if you don't have qsort_r, you can use the callback(3) package from the ffcall library to create closures at runtime. Example:
#include <callback.h>
void comp_base(void *data, va_alist alist)
{
va_start_int(alist); // return type will be int
int L = (int)data;
const void *a = va_arg_ptr(alist, const void*);
const void *b = va_arg_ptr(alist, const void*);
// Now that we know L, compare
int return_value = comp(a, b, L);
va_return_int(alist, return_value); // return return_value
}
...
// In a function somewhere
typedef int (*compare_func)(const void*, const void*);
// Create some closures with different L values
compare_func comp1 = (compare_func)alloc_callback(&comp_base, (void *)L1);
compare_func comp2 = (compare_func)alloc_callback(&comp_base, (void *)L2);
...
// Use comp1 & comp2, e.g. as parameters to qsort
...
free_callback(comp1);
free_callback(comp2);
Note that the callback library is threadsafe, since all parameters are passed on the stack or in registers. The library takes care of allocating memory, making sure that memory is executable, and flushing the instruction cache if necessary to allow dynamically generated code (that is, the closure) to be executed at runtime. It supposedly works on a large variety of systems, but it's also quite possible that it won't work on yours, either due to bugs or lack of implementation.
Also note that this adds a little bit of overhead to the function call. Each call to comp_base() above has to unpack its arguments from the list passed it (which is in a highly platform-dependent format) and stuff its return value back in. Most of the time, this overhead is miniscule, but for a comparison function where the actual work performed is very small and which will get called many, many times during a call to qsort(), the overhead is very significant.
std::array< std::array<int, L>, N > array;
// or std::vector< std::vector<int> > if N*L is not a constant
std::sort( array.begin(), array.end() );
I'm not sure if you can achieve the same result without a lot more work. std::sort() is made to sort sequences of elements defined by two random access iterators. Unfortunately, it determines the type of the element from the iterator. For example:
std::sort(&array[0], &array[N + L]);
will sort all of the elements of array. The problem is that it assumes that the subscripting, increment, decrement, and other indexing operators of the iterator step over elements of the sequence. I believe that the only way that you can sort slices of the array (I think that this is what you are after), is to write an iterator that indexes based on L. This is what sellibitze has done in the stride_iterator answer.
namespace
{
struct NewCompare
{
bool operator()( const int a, const int b ) const
{
return a < b;
}
};
}
std::sort(array+start,array+start+L,NewCompare);
Do test with std::stable_sort() on realistic data-sets - for some data mixes its substantially faster!
On many compilers (GCC iirc) there's a nasty bite: the std::sort() template asserts that the comparator is correct by testing it TWICE, once reversed, to ensure the result is reversed! This will absolutely completely kill performance for moderate datasets in normal builds. The solution is something like this:
#ifdef NDEBUG
#define WAS_NDEBUG
#undef NDEBUG
#endif
#define NDEBUG
#include <algorithm>
#ifdef WAS_NDEBUG
#undef WAS_NDEBUG
#else
#undef NDEBUG
#endif
Adapted from this excellent blog entry: http://www.tilander.org/aurora/2007/12/comparing-stdsort-and-qsort.html
Arkadiy has the right idea. You can sort in place if you create an array of pointers and sort that:
#define NN 7
#define LL 4
int array[NN*LL] = {
3, 5, 5, 5,
3, 6, 6, 6,
4, 4, 4, 4,
4, 3, 3, 3,
2, 2, 2, 2,
2, 0, 0, 0,
1, 1, 1, 1
};
struct IntPtrArrayComp {
int length;
IntPtrArrayComp(int len) : length(len) {}
bool operator()(int* const & a, int* const & b) {
for (int i = 0; i < length; ++i) {
if (a[i] < b[i]) return true;
else if (a[i] > b[i]) return false;
}
return false;
}
};
void sortArrayInPlace(int* array, int number, int length)
{
int** ptrs = new int*[number];
int** span = ptrs;
for (int* a = array; a < array+number*length; a+=length) {
*span++ = a;
}
std::sort(ptrs, ptrs+number, IntPtrArrayComp(length));
int* buf = new int[number];
for (int n = 0; n < number; ++n) {
int offset = (ptrs[n] - array)/length;
if (offset == n) continue;
// swap
int* a_n = array+n*length;
std::move(a_n, a_n+length, buf);
std::move(ptrs[n], ptrs[n]+length, a_n);
std::move(buf, buf+length, ptrs[n]);
// find what is pointing to a_n and point it
// to where the data was move to
int find = 0;
for (int i = n+1; i < number; ++i) {
if (ptrs[i] == a_n) {
find = i;
break;
}
}
ptrs[find] = ptrs[n];
}
delete[] buf;
delete[] ptrs;
}
int main()
{
for (int n = 0; n< NN; ++n) {
for (int l = 0; l < LL; ++l) {
std::cout << array[n*LL+l];
}
std::cout << std::endl;
}
std::cout << "----" << std::endl;
sortArrayInPlace(array, NN, LL);
for (int n = 0; n< NN; ++n) {
for (int l = 0; l < LL; ++l) {
std::cout << array[n*LL+l];
}
std::cout << std::endl;
}
return 0;
}
Output:
3555
3666
4444
4333
2222
2000
1111
----
1111
2000
2222
3555
3666
4333
4444
A lot of these answers seem like overkill. If you really have to do it C++ style, using jmucchiello's example:
template <int Length>
struct Block
{
int n_[Length];
bool operator <(Block const &rhs) const
{
for (int i(0); i < Length; ++i)
{
if (n_[i] < rhs.n_[i])
return true;
else if (n_[i] > rhs.n_[i])
return false;
}
return false;
}
};
and then sort with:
sort((Block<4> *)&array[0], (Block<4> *)&array[NN]);
It doesn't have to be any more complicated.