Given a class Foo which has some value-initializing default constructor:
class Foo {
private:
uint32_t x;
public:
constexpr Foo()
: x { 3 }
{}
// ... and some other constructors
};
I need to allocate an array of these Foo's. I don't want the array's elements' default constructors to run, because later I'm going to initialize each element explicitly anyway. Something like this:
Foo foos[20000];
for (int i = 0; i < 20000; ++i) {
foos[i] = init(i);
}
Is there a way to obtain such an uninitialized array of Foo's given that we're not allowed to change the default constructor of Foo into a non-initializing one?
By the way, this is how you'd create an uninitialized array in D:
Foo[20000] foos = void;
...and here's the same in Rust:
let mut foos: [Foo; 20000] = unsafe { std::mem::uninitialized() };
If you using C++11, you can use std::vector and emplace_back()
vector<Foo> foos;
for(int i = 0; i < 20000; ++i)
foos.emplace_back( /* arguments here */);
Perhaps this answers the question at hand more accurately?
#include <type_traits>
class Foo {
private:
uint32_t x;
public:
constexpr Foo()
: x { 3 }
{}
constexpr Foo(uint32_t n)
: x { n * n }
{}
};
// ...and then in some function:
typename std::aligned_storage<sizeof(Foo), alignof(Foo)>::type foos[20000];
for (int i = 0; i < 20000; ++i) {
new (foos + i) Foo(i);
}
The drawback seems to be that you can use only a constructor to initialize those elements, and not a free function or anything else.
Question: Can I then access those Foo's like this:
Foo* ptr = reinterpret_cast<Foo*>(foos);
ptr[50] = Foo();
What you might be looking for is std::get_temporary_buffer:
int main()
{
size_t n = 20000;
auto buf = std::get_temporary_buffer<Foo>(n);
if (buf.second<n) {
std::cerr << "Couldn't allocate enough memory\n";
return EXIT_FAILURE;
}
// ...
std::raw_storage_iterator<Foo*,Foo> iter(buf.first);
for (int i = 0; i < n; ++i) {
*iter++ = Foo();
}
// ...
std::return_temporary_buffer(buf.first);
}
Related
struct Mystruct
{
int x;
int y;
Mystruct(int x, int y);
}
------------------------
class Myclass
{
Mystruct** p;
Myclass(int n);
}
------------------------
Myclass::Myclass(int n)
{
this->p = new Mystruct*[n];
for ( int i = 0; i < n; i++ )
this->p[i] = new Mystruct[n];
}
This will not work. I know the problem lies somewhere with default constructor not being available, but I do not know how to move forward from here.
you want
Myclass::Myclass(int n)
{
this->p = new Mystruct*[n];
for ( int i = 0; i < n; i++ )
this->p[i] = new Mystruct[n];
}
because Mystruct** p;
You also need to save the dimension, and to add a destructor, very probably the constructor must be public.
As said in a remark to be able to allocate your array of Mystruct that one need a constructor without parameter
How can I return an array from a method, and how must I declare it?
int[] test(void); // ??
int* test();
but it would be "more C++" to use vectors:
std::vector< int > test();
EDIT
I'll clarify some point. Since you mentioned C++, I'll go with new[] and delete[] operators, but it's the same with malloc/free.
In the first case, you'll write something like:
int* test() {
return new int[size_needed];
}
but it's not a nice idea because your function's client doesn't really know the size of the array you are returning, although the client can safely deallocate it with a call to delete[].
int* theArray = test();
for (size_t i; i < ???; ++i) { // I don't know what is the array size!
// ...
}
delete[] theArray; // ok.
A better signature would be this one:
int* test(size_t& arraySize) {
array_size = 10;
return new int[array_size];
}
And your client code would now be:
size_t theSize = 0;
int* theArray = test(theSize);
for (size_t i; i < theSize; ++i) { // now I can safely iterate the array
// ...
}
delete[] theArray; // still ok.
Since this is C++, std::vector<T> is a widely-used solution:
std::vector<int> test() {
std::vector<int> vector(10);
return vector;
}
Now you don't have to call delete[], since it will be handled by the object, and you can safely iterate it with:
std::vector<int> v = test();
std::vector<int>::iterator it = v.begin();
for (; it != v.end(); ++it) {
// do your things
}
which is easier and safer.
how can i return a array in a c++ method and how must i declare it? int[] test(void); ??
This sounds like a simple question, but in C++ you have quite a few options. Firstly, you should prefer...
std::vector<>, which grows dynamically to however many elements you encounter at runtime, or
std::array<> (introduced with C++11), which always stores a number of elements specified at compile time,
...as they manage memory for you, ensuring correct behaviour and simplifying things considerably:
std::vector<int> fn()
{
std::vector<int> x;
x.push_back(10);
return x;
}
std::array<int, 2> fn2() // C++11
{
return {3, 4};
}
void caller()
{
std::vector<int> a = fn();
const std::vector<int>& b = fn(); // extend lifetime but read-only
// b valid until scope exit/return
std::array<int, 2> c = fn2();
const std::array<int, 2>& d = fn2();
}
The practice of creating a const reference to the returned data can sometimes avoid a copy, but normally you can just rely on Return Value Optimisation, or - for vector but not array - move semantics (introduced with C++11).
If you really want to use an inbuilt array (as distinct from the Standard library class called array mentioned above), one way is for the caller to reserve space and tell the function to use it:
void fn(int x[], int n)
{
for (int i = 0; i < n; ++i)
x[i] = n;
}
void caller()
{
// local space on the stack - destroyed when caller() returns
int x[10];
fn(x, sizeof x / sizeof x[0]);
// or, use the heap, lives until delete[](p) called...
int* p = new int[10];
fn(p, 10);
}
Another option is to wrap the array in a structure, which - unlike raw arrays - are legal to return by value from a function:
struct X
{
int x[10];
};
X fn()
{
X x;
x.x[0] = 10;
// ...
return x;
}
void caller()
{
X x = fn();
}
Starting with the above, if you're stuck using C++03 you might want to generalise it into something closer to the C++11 std::array:
template <typename T, size_t N>
struct array
{
T& operator[](size_t n) { return x[n]; }
const T& operator[](size_t n) const { return x[n]; }
size_t size() const { return N; }
// iterators, constructors etc....
private:
T x[N];
};
Another option is to have the called function allocate memory on the heap:
int* fn()
{
int* p = new int[2];
p[0] = 0;
p[1] = 1;
return p;
}
void caller()
{
int* p = fn();
// use p...
delete[] p;
}
To help simplify the management of heap objects, many C++ programmers use "smart pointers" that ensure deletion when the pointer(s) to the object leave their scopes. With C++11:
std::shared_ptr<int> p(new int[2], [](int* p) { delete[] p; } );
std::unique_ptr<int[]> p(new int[3]);
If you're stuck on C++03, the best option is to see if the boost library is available on your machine: it provides boost::shared_array.
Yet another option is to have some static memory reserved by fn(), though this is NOT THREAD SAFE, and means each call to fn() overwrites the data seen by anyone keeping pointers from previous calls. That said, it can be convenient (and fast) for simple single-threaded code.
int* fn(int n)
{
static int x[2]; // clobbered by each call to fn()
x[0] = n;
x[1] = n + 1;
return x; // every call to fn() returns a pointer to the same static x memory
}
void caller()
{
int* p = fn(3);
// use p, hoping no other thread calls fn() meanwhile and clobbers the values...
// no clean up necessary...
}
It is not possible to return an array from a C++ function. 8.3.5[dcl.fct]/6:
Functions shall not have a return type of type array or function[...]
Most commonly chosen alternatives are to return a value of class type where that class contains an array, e.g.
struct ArrayHolder
{
int array[10];
};
ArrayHolder test();
Or to return a pointer to the first element of a statically or dynamically allocated array, the documentation must indicate to the user whether he needs to (and if so how he should) deallocate the array that the returned pointer points to.
E.g.
int* test2()
{
return new int[10];
}
int* test3()
{
static int array[10];
return array;
}
While it is possible to return a reference or a pointer to an array, it's exceedingly rare as it is a more complex syntax with no practical advantage over any of the above methods.
int (&test4())[10]
{
static int array[10];
return array;
}
int (*test5())[10]
{
static int array[10];
return &array;
}
Well if you want to return your array from a function you must make sure that the values are not stored on the stack as they will be gone when you leave the function.
So either make your array static or allocate the memory (or pass it in but your initial attempt is with a void parameter). For your method I would define it like this:
int *gnabber(){
static int foo[] = {1,2,3}
return foo;
}
"how can i return a array in a c++ method and how must i declare it?
int[] test(void); ??"
template <class X>
class Array
{
X *m_data;
int m_size;
public:
// there constructor, destructor, some methods
int Get(X* &_null_pointer)
{
if(!_null_pointer)
{
_null_pointer = new X [m_size];
memcpy(_null_pointer, m_data, m_size * sizeof(X));
return m_size;
}
return 0;
}
};
just for int
class IntArray
{
int *m_data;
int m_size;
public:
// there constructor, destructor, some methods
int Get(int* &_null_pointer)
{
if(!_null_pointer)
{
_null_pointer = new int [m_size];
memcpy(_null_pointer, m_data, m_size * sizeof(int));
return m_size;
}
return 0;
}
};
example
Array<float> array;
float *n_data = NULL;
int data_size;
if(data_size = array.Get(n_data))
{ // work with array }
delete [] n_data;
example for int
IntArray array;
int *n_data = NULL;
int data_size;
if(data_size = array.Get(n_data))
{ // work with array }
delete [] n_data;
I have an interface which multiple classes inheritance.
class someInterface
{
virtual void someMethod() = 0;
}
class A : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class B : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class C : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
For each of the classes A, B, C i have created an array with different sizes of their actual type inside a container class.
class AContainer
{
public:
A As[10];
}
class BContainer
{
public:
B Bs[5];
}
etc...
Furthermore i have an array of pointers to "SomeInterface", where i want to have a pointer to each of the actual arrays like this.
#define SOMEINTERRFACE_SIZE 3
someInterface *array[SOMEINTERRFACE_SIZE];
array[0] = AContainer.As; //Could also just be &AContainer.As[0]
array[1] = BContainer.Bs;
array[2] = CContainer.Cs;
for (int i = 0; i < SOMEINTERRFACE_SIZE; ++i)
{
int elements = //Here i need a solution to get the size
//So i can iterate through the array, which the pointer points to.
for (int i = 0; i < elements; ++i)
{
//Call the interface method on each element.
}
}
The problem occurs, when i have to use the someInterface array, since it isn't possible to get the size of the actual array through the someInterface pointer..
What is a good solution to this problem? I really need some help to solve this.
Also don't want to use dynamic allocation, so no solution with vector<> or malloc etc. because I'm writing to an Arduino.
It won't work. In C++ you have to know the size of the elements in an array. A, B, and C might be different sizes, so you can't treat arrays of them the same.
&AContainer.As[i] == &AContainer.As + i * sizeof(A)
but
&BContainer.Bs[i] == &BContainer.Bs + i * sizeof(B)
So it's impossible for the same machine code to iterate over arrays of A and of B. If you want to iterate over an array of objects, you need to know the exact type.
Remember in C++, if you want to get a polymorphic virtual call, you need to go through pointer or reference. The solution is to copy pointers to the elements in each array into one "master" array.
SomeInterface *ptrs[NUM_A + NUM_B + NUM_C];
SomeInterface **dest = ptrs;
for (int i = 0; i < NUM_A; ++i) {
*dest++ = &AContainer.As[i];
}
for (int i = 0; i < NUM_B; ++i) {
*dest++ = &BContainer.Bs[i];
}
// et cetera...
This only uses a little bit of extra space because you're storing pointers, not actual objects.
EDIT: I guess you could do something like this if you really want to save the space:
someInterface *arrays[] = { AContainer.As, BContainer.Bs, CContainer.Cs };
int objSizes[] = { sizeof(A), sizeof(B), sizeof(C) };
int arrLengths[] = { NUM_A, NUM_B, NUM_C };
for (int j = 0; j < sizeof(arrays)/sizeof(arrays[0]); ++j)
{
void *ptr = arrays[j];
for (int i = 0; i < arrLengths[j]; ++i) {
someInterface *iptr = (someInterface *)ptr;
iptr->method();
ptr += objSizes[j];
}
}
(this is untested, you might need to tweak a little.)
In theory since all those arrays are full of compile-time constants, it should optimize out to something fast. If it doesn't, the code will run slower because it will be incrementing pointers by a value only known at runtime instead of compile time. You should check the assembly output if you really care about speed.
Difficult to answer without knowing more details of your application - but here a a few ideas that might help.
Given:
class someInterface { public: virtual char someMethod() = 0; };
class A : public someInterface { public: char someMethod() { return 'A'; } };
class B : public someInterface { public: char someMethod() { return 'B'; } };
class C : public someInterface { public: char someMethod() { return 'C'; } };
You could hand-roll something like this:
class Array {
public:
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < countA ; ++i) function(As[i]);
for (size_t i = 0 ; i < countB ; ++i) function(Bs[i]);
for (size_t i = 0 ; i < countC ; ++i) function(Cs[i]);
}
private:
enum {countA = 10, countB = 5, countC = 3};
A As[countA];
B Bs[countB];
C Cs[countC];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array array;
array.forEach(doSomeMethod);
return 0;
}
Note that by using the "callback" function doSomeMethod, we get around a typical problem of dispatching in polymorphic collections.
Of course, you don't want to keep hand-rolling things like that. Fortuanately the Arduino C++ compiler I checked out has template support, so you could do something like:
template <class T, size_t _size, class NextArray = void>
struct Array {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
nextArray.forEach(function);
}
private:
T elements[_size];
NextArray nextArray;
};
template <class T, size_t _size>
struct Array<T, _size, void> {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
}
private:
T elements[_size];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array<A, 10, Array<B, 5, Array<C, 3> > > array;
array.forEach(doSomeMethod);
return 0;
}
Which gets the compiler to write it for you for different combinations of types and sizes. A few things worth noting:
All the magic is done at compile time. Check out the assembly generated by an optimising compiler to see how small and fast this can be.
Read up on c++ "functors" if your callback function needs some state.
If your compiler supports variadic templates and/or lambdas, this becomes simpler (I'm assuming the Arduido compiler doesn't yet)
If you can't use the callback approach (and your compiler doesn't support lambdas yet), then you could try this next option, which incurs some small run-time cost over the option given above:
template <class Interface>
class ArrayInterface {
public:
virtual size_t getSize() = 0;
virtual Interface& getElement(size_t index) = 0;
};
template <class T, class Interface, size_t size>
class Array : public ArrayInterface<Interface> {
public:
size_t getSize() { return size; }
Interface& getElement(size_t index) { return element[index]; }
private:
T element[size];
};
int main(int, char**) {
Array<A, SomeInterface, 10> As;
Array<B, SomeInterface, 5> Bs;
Array<C, SomeInterface, 3> Cs;
const int SOMEINTERRFACE_SIZE = 3;
ArrayInterface<SomeInterface>* array[SOMEINTERRFACE_SIZE] = {&As, &Bs, &Cs};
for (size_t i = 0 ; i < SOMEINTERRFACE_SIZE ; ++i) {
ArrayInterface<SomeInterface>& innerArray = *array[i];
for (size_t j = 0 ; j < innerArray.getSize() ; ++j)
std::cout << innerArray.getElement(j).someMethod();
}
return 0;
}
(This last one uses an outer array of pointers, as per your question)
This post is already too long, so I haven't gone into much detail, or delved into options such as a single, flat array of member function pointers. If you have any questions, just shout.
Is it what you are trying to achive?
Iterate over a list of objects and call a reimplemented method of a common interface?
Put this piece of code anywhere in global C++ scope for testing.
#include <vector>
#include <iostream>
int TestSomewhereInCppGlobalScopeCode()
{
class someInterface
{
public:
virtual void someMethod() = 0;
};
class A : public someInterface
{
public:
void someMethod()
{
std::cout << "A::someMethod()";
}
};
class B : public someInterface
{
public:
void someMethod()
{
std::cout << "B::someMethod()";
}
};
class C : public someInterface
{
public:
void someMethod()
{
std::cout << "C::someMethod()";
}
};
std::vector<someInterface*> ListOfObjectsHavingCommonInterface;
ListOfObjectsHavingCommonInterface.push_back( new A );
ListOfObjectsHavingCommonInterface.push_back( new B );
ListOfObjectsHavingCommonInterface.push_back( new C );
for ( std::vector<someInterface*>::iterator it = ListOfObjectsHavingCommonInterface.begin();
it != ListOfObjectsHavingCommonInterface.end();
++it )
{
(*it)->someMethod();
}
return 0;
}
static int TestSomewhereInCppGlobalScopeCode_Caller = TestSomewhereInCppGlobalScopeCode();
I have a class with a multidimensional array:
it is possible to create a one, two, ..., n dimensional array with this class
if the array has n dimensions, i want to use n operator[] to get an object:
example:
A a({2,2,2,2}];
a[0][1][1][0] = 5;
but array is not a vector of pointer which lead to other vectors etc...
so i want the operator[] to return a class object until the last dimension, then return a integer
This is a strongly simplified code, but it shows my problem:
The error i receive: "[Error] cannot convert 'A::B' to 'int' in initialization"
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <iostream> // cin, cout...
class A {
private:
static int* a;
public:
static int dimensions;
A(int i=0) {
dimensions = i;
a = new int[5];
for(int j=0; j<5; j++) a[j]=j;
};
class B{
public:
B operator[](std::ptrdiff_t);
};
class C: public B{
public:
int& operator[](std::ptrdiff_t);
};
B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
B res;
if (dimensions <= 1){
res = C();
}
else{
res = B();
}
dimensions--;
return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
B res;
if (dimensions <=1){
res = B();
}
else{
res = C();
}
dimensions--;
return res;
}
int& A::C::operator[](std::ptrdiff_t i){
return *(a+i);
}
int main(){
A* obj = new A(5);
int res = obj[1][1][1][1][1];
std::cout<< res << std::endl;
}
The operator[] is evaluated from left to right in obj[1][1]...[1], so obj[1] returns a B object. Suppose now you just have int res = obj[1], then you'll assign to a B object (or C object in the case of multiple invocations of []) an int, but there is no conversion from B or C to int. You probably need to write a conversion operator, like
operator int()
{
// convert to int here
}
for A, B and C, as overloaded operators are not inherited.
I got rid of your compiling error just by writing such operators for A and B (of course I have linking errors since there are un-defined functions).
Also, note that if you want to write something like obj[1][1]...[1] = 10, you need to overload operator=, as again there is no implicit conversion from int to A or your proxy objects.
Hope this makes sense.
PS: see also #Oncaphillis' comment!
vsoftco is totally right, you need to implement an overload operator if you want to actually access your elements. This is necessary if you want it to be dynamic, which is how you describe it. I actually thought this was an interesting problem, so I implemented what you described as a template. I think it works, but a few things might be slightly off. Here's the code:
template<typename T>
class nDimArray {
using thisT = nDimArray<T>;
T m_value;
std::vector<thisT*> m_children;
public:
nDimArray(std::vector<T> sizes) {
assert(sizes.size() != 0);
int thisSize = sizes[sizes.size() - 1];
sizes.pop_back();
m_children.resize(thisSize);
if(sizes.size() == 0) {
//initialize elements
for(auto &c : m_children) {
c = new nDimArray(T(0));
}
} else {
//initialize children
for(auto &c : m_children) {
c = new nDimArray(sizes);
}
}
}
~nDimArray() {
for(auto &c : m_children) {
delete c;
}
}
nDimArray<T> &operator[](const unsigned int index) {
assert(!isElement());
assert(index < m_children.size());
return *m_children[index];
}
//icky dynamic cast operators
operator T() {
assert(isElement());
return m_value;
}
T &operator=(T value) {
assert(isElement());
m_value = value;
return m_value;
}
private:
nDimArray(T value) {
m_value = value;
}
bool isElement() const {
return m_children.size() == 0;
}
//no implementation yet
nDimArray(const nDimArray&);
nDimArray&operator=(const nDimArray&);
};
The basic idea is that this class can either act as an array of arrays, or an element. That means that in fact an array of arrays COULD be an array of elements! When you want to get a value, it tries to cast it to an element, and if that doesn't work, it just throws an assertion error.
Hopefully it makes sense, and of course if you have any questions ask away! In fact, I hope you do ask because the scope of the problem you describe is greater than you probably think it is.
It could be fun to use a Russian-doll style template class for this.
// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
foo<d-1, n> data[n];
public:
foo<d-1, n>& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
int data[n];
public:
int& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
int main(int argc, char** argv)
{
foo<3, 10> myFoo;
for(int i=0; i<10; ++i)
for(int j=0; j<10; ++j)
for(int k=0; k<10; ++k)
myFoo[i][j][k] = i*10000 + j*100 + k;
return myFoo[9][9][9]; // would be 090909 in this case
}
Each dimension keeps an array of previous-dimension elements. Dimension 1 uses the base specialization that tracks a 1D int array. Dimension 2 would then keep an array of one-dimentional arrays, D3 would have an array of two-dimensional arrays, etc. Then access looks the same as native multi-dimensional arrays. I'm using arrays inside the class in my example. This makes all the memory contiguous for the n-dimensional arrays, and doesn't require dynamic allocations inside the class. However, you could provide the same functionality with dynamic allocation as well.
I have a C++ class template that makes an Array of pointers. This also gets typedefed to make Arrays of Arrays and so on:
typedef Array<Elem> ElemArray;
typedef Array<ElemArray> ElemArrayArray;
typedef Array<ElemArrayArray> ElemArrayArrayArray;
I would like to be able to set one leaf node from another by copying the pointer so they both refer to the same Elem.
But I also want to be able to set one Array (or Array of Arrays etc) from another. In this case I don't want to copy the pointers, I want to keep the arrays seperate and descend into each one until I get to the leaf node, at where I finally copy the pointers.
I have code that does this (below). When you set something in an Array it calls a CopyIn method to do the copying.
But because this is templated it also has to call the CopyIn method on the leaf class, which means I have to add a dummy method to every leaf class that just returns false.
I have also tried adding a flag to the template to tell it whether it contains Arrays or not, and so whether to call the CopyIn method. This works fine - the CopyIn method of the leaf nodes never gets called, but it still has to be there for the compile to work!
Is there a better way to do this?
#include <stdio.h>
class Elem {
public:
Elem(int v) : mI(v) {}
void Print() { printf("%d\n",mI); }
bool CopyIn(Elem *v) { return false; }
int mI;
};
template < typename T > class Array {
public:
Array(int size) : mB(0), mN(size) {
mB = new T* [size];
for (int i=0; i<mN; i++)
mB[i] = new T(mN);
}
~Array() {
for (int i=0; i<mN; i++)
delete mB[i];
delete [] mB;
}
T* Get(int i) { return mB[i]; }
void Set(int i, T* v) {
if (! mB[i]->CopyIn(v) ) {
// its not an array, so copy the pointer
mB[i] = v;
}
}
bool CopyIn(Array<T>* v) {
for (int i=0; i<mN; i++) {
if (v && i < v->mN ) {
if ( ! mB[i]->CopyIn( v->mB[i] )) {
// its not an array, so copy the pointer
mB[i] = v->mB[i];
}
}
else {
mB[i] = 0;
}
}
return true; // we did the copy, no need to copy pointer
}
void Print() {
for (int i=0; i<mN; i++) {
printf("[%d] ",i);
mB[i]->Print();
}
}
private:
T **mB;
int mN;
};
typedef Array<Elem> ElemArray;
typedef Array<ElemArray> ElemArrayArray;
typedef Array<ElemArrayArray> ElemArrayArrayArray;
int main () {
ElemArrayArrayArray* a = new ElemArrayArrayArray(2);
ElemArrayArrayArray* b = new ElemArrayArrayArray(3);
// In this case I need to copy the pointer to the Elem into the ElemArrayArray
a->Get(0)->Get(0)->Set(0, b->Get(0)->Get(0)->Get(0));
// in this case I need go down through a and b until I get the to Elems
// so I can copy the pointers
a->Set(1,b->Get(2));
b->Get(0)->Get(0)->Get(0)->mI = 42; // this will also set a[0,0,0]
b->Get(2)->Get(1)->Get(1)->mI = 96; // this will also set a[1,1,1]
// should be 42,2, 2,2, 3,3, 3,96
a->Print();
}
You could use template specialization to do something different with the leaf class:
template <> class Array<Elem> {
// Define how Array<Elem> should behave
}
As others mentioned in the comments, you should really consider using operator [] instead of Get and Set methods for array indexes.
I rearranged the code a bit to use template specialization, now the normal Set does a deep copy like this:
void Set(int i, T* v) { mB[i]->CopyIn(v); }
but for the array that contains the leaves you have to add the specialization:
template <> void Array<Elem>::Set(int i, Elem* v) { SetPtr(i,v); }
Of course you have to add a new one of these for every different leaf class. At least if you forget to do this you get a compiler error because it can't find CopyIn in the Elem class.
I thought about replacing CopyIn with an overloaded assignment operator, but this would loose the compile warning if you forgot to add the specialization.
I also thought about doing operator[] instead of Get and Set (just for this example), but it seems a bit dangerous with all these pointers flying around - it's easy to write a[0] instead of (*a)[0]. Also I couldn't work out the magic needed to convert the pointer in the Array into the correct sort of reference for [] to return (anyone know how to do that?).
#include <stdio.h>
class Elem {
public:
Elem(int v) : mI(v) {}
void Print() { printf("%d\n",mI); }
int mI;
};
template < typename T > class Array {
public:
Array(int size) : mB(0), mN(size) {
mB = new T* [size];
for (int i=0; i<mN; i++)
mB[i] = new T(mN);
}
~Array() {
for (int i=0; i<mN; i++)
delete mB[i];
delete [] mB;
}
T* Get(int i) { return (i<mN) ? mB[i] : 0; }
void Set(int i, T* v) { mB[i]->CopyIn(v); }
void SetPtr(int i, Elem* v) { mB[i] = v; }
bool CopyIn(Array<T>* v) {
for (int i=0; i<mN; i++) {
if (v && i < v->mN ) {
Set( i, v->Get(i) );
}
else {
mB[i] = 0;
}
}
}
void Print() {
for (int i=0; i<mN; i++) {
printf("[%d] ",i);
mB[i]->Print();
}
}
private:
T** mB;
int mN;
};
typedef Array<Elem> ElemArray;
typedef Array<ElemArray> ElemArrayArray;
typedef Array<ElemArrayArray> ElemArrayArrayArray;
template <> void Array<Elem>::Set(int i, Elem* v) { SetPtr(i,v); }
int main () {
ElemArrayArrayArray* a = new ElemArrayArrayArray(2);
ElemArrayArrayArray* b = new ElemArrayArrayArray(3);
// In this case I need to copy the pointer to the Elem into the ElemArrayArray
a->Get(0)->Get(0)->Set(0, b->Get(0)->Get(0)->Get(0));
// in this case I need go down through a and b until I get the to Elems
// so I can copy the pointers
a->Set(1,b->Get(2));
b->Get(0)->Get(0)->Get(0)->mI = 42; // this will also set a[0,0,0]
b->Get(2)->Get(1)->Get(1)->mI = 96; // this will also set a[1,1,1]
// should be 42,2, 2,2, 3,3, 3,96
a->Print();
}