C/C++ Help
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
 
User Name:
Password:
Remember me
 



Go Back   Dev Articles Community ForumsProgrammingC/C++ Help

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Display Modes
 
Unread Dev Articles Community Forums Sponsor:
  #1  
Old January 29th, 2009, 10:32 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Classes - How to pass arguments to constructor when using Vector(STL)?

Hello,

I'm trying to create an array of Matrices. Matrix is defined in third party ARPREC Library:

C++ Code:
Original - C++ Code
  1. template <class T>
  2. class matrix : public matrix_base<T> {
  3. protected:
  4.   matrix (matrix<T> &a) { }
  5. public:
  6.   matrix(int n0, int m0 = 1) : matrix_base<T>(n0, m0) {
  7.     matrix_base<T>::elements = new T[m0 * n0];
  8.   }
  9.  
  10.   ~matrix() {
  11.     delete [] matrix_base<T>::elements;
  12.   }
  13. };


Please note that the constructor of the class matrix takes the dimension of the matrix as input. When I try to build a vector (using STL Vector class) of length 10 of such matrices:
C++ Code:
Original - C++ Code
  1. vector <  matrix<mp_real> > b(10);

the compiler gives me:

error: no instance of constructor "matrix<mp_real>::matrix" matches the argument list
vector(size_type __n, const value_type& __value = value_type(),
^
detected during instantiation of "std::vector<_Tp, _Alloc>::vector(size_t={unsigned long}, const _Tp &, const _Alloc &) [with _Tp=matrix<mp_real>, _Alloc=std::allocator<matrix<mp_real>>]"


Of course, the compiler is right. There is no matrix<mp_real>::matrix constructor. There is just matrix<mp_real>::matrix (n,m) constructor.

So the question is
How can I tell to Vector which constructor (or which arguments to the constructor) should it take?


Please notice that I have a workaround:
C++ Code:
Original - C++ Code
  1. vector <  matrix<mp_real> > b;
  2. b.reserve(10);
  3. matrix<mp_real> m(1000,1000);
  4. m(i,j)=func(i,j); //for all i and j
  5. b.push_back(m);


What I don't like about this solution is that b.push_back(m) will copy matrix m to the vector b. So I fill up the matrix m and copy it's contents to the vector. Please note that constructor matrix<mp_real> m(1000,1000); just allocates memory space but will leave the memory uninitialized. So the solution with
C++ Code:
Original - C++ Code
  1. vector <  matrix<mp_real> > b(10);

would be much more efficient since it would just call constructor 10 times (just allocating memory) and enabling me to directly write into this memory (rather than copying it from matrix m).

Does anybody has an idea how can pass arguments of class T constructor when writing
vector < T > b(10);

Thanks a lot!
Jiri

Reply With Quote
  #2  
Old January 29th, 2009, 11:06 AM
C++101 C++101 is offline
Contributing User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 136 C++101 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 Day 3 h 16 m 6 sec
Reputation Power: 10
Use a list that will grow dynamically and wont create copies. Vector won't work for you because of just what your saying it will just create copies. Sorry if you read my other post lol I didn't read your entire post till now.

Reply With Quote
  #3  
Old January 29th, 2009, 11:22 AM
C++101 C++101 is offline
Contributing User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 136 C++101 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 Day 3 h 16 m 6 sec
Reputation Power: 10
Also you can create your own SLL and then you wont get the bloat of the STL unless you are using all of it.

Reply With Quote
  #4  
Old January 29th, 2009, 11:51 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Hi,

yes, I was thinking about using the list. However, vector has the benefit that it will store all values in one chunk of memory just making random memory access quicker.

Actually,

I could create a new allocator class:
template < class T, class Allocator = allocator<T> > class vector;

but seems to be too much work just to pass matrix size to the constructor of class matrix....

Anyhow, thanks for the hints!
Jiri

Reply With Quote
  #5  
Old January 29th, 2009, 02:43 PM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
If you make the copy constructor public and add a const to its parameter then you can do something like this:
Code:
vector <  matrix<mp_real> > b( 10, matrix<mp_real>(1000,1000) ); 
Of course this means you will have to have an efficient copy constructor which like your constructor leaves the memory uninitialised.
All of this can also be accomplished using resize() (preferably with a suitable reserve() to prevent extra copying due to reallocation).

By the way, you can leave the template argument out of the copy constructor:
Code:
matrix (const matrix &a) { ... }
Lists are horrible for efficient matrix computations, the memory is more fragmented which means less benefit from locality of reference (i.e., cache and such).
__________________
There is no such thing as C/C++, you either program C or C++

Last edited by Icon : January 29th, 2009 at 02:50 PM.

Reply With Quote
  #6  
Old January 29th, 2009, 03:13 PM
C++101 C++101 is offline
Contributing User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 136 C++101 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 Day 3 h 16 m 6 sec
Reputation Power: 10
They all have there place. I.E. if you have a lot of pointers to objects that are stored in your container since the vector makes a copy of itself you'll loose all you spots.

Do you know why this is? And why vectors access is O(1)?

Reply With Quote
  #7  
Old January 29th, 2009, 03:27 PM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
Yes. Indexing in a vector comes down to calculating an offset, in a list you have to linearly follow the pointer trail. But my point was that sequential reads in a vector can benefit from locality since the OS could load multiple elements at the same time (look up paging and caching). This is something that is more difficult for a list. The theoretical complexity has nothing to do with this.

Reply With Quote
  #8  
Old January 29th, 2009, 03:30 PM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
What exactly do you mean by spots? Are you referring to possible moving of memory due to a reallocation in the vector?

Reply With Quote
  #9  
Old January 29th, 2009, 03:35 PM
C++101 C++101 is offline
Contributing User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 136 C++101 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 Day 3 h 16 m 6 sec
Reputation Power: 10
Correct, cool thanks for the info.

Reply With Quote
  #10  
Old January 29th, 2009, 03:38 PM
C++101 C++101 is offline
Contributing User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 136 C++101 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 Day 3 h 16 m 6 sec
Reputation Power: 10
Awesome learn something new everyday.

Reply With Quote
  #11  
Old January 30th, 2009, 01:51 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
@OP, does what I posted earlier accomplish what you wanted?

Reply With Quote
  #12  
Old January 30th, 2009, 05:28 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Quote:
Originally Posted by Icon
If you make the copy constructor public and add a const to its parameter then you can do something like this:
Code:
vector <  matrix<mp_real> > b( 10, matrix<mp_real>(1000,1000) ); 
Of course this means you will have to have an efficient copy constructor which like your constructor leaves the memory uninitialized.
All of this can also be accomplished using resize() (preferably with a suitable reserve() to prevent extra copying due to reallocation).

By the way, you can leave the template argument out of the copy constructor:
Code:
matrix (const matrix &a) { ... }
Lists are horrible for efficient matrix computations, the memory is more fragmented which means less benefit from locality of reference (i.e., cache and such).


Hi Icon,

thanks for the hint! The first one
C++ Code:
Original - C++ Code
  1. vector <  matrix<mp_real> > b( 10, matrix<mp_real>(1000,1000) );

will just copy the matrix over and over.

Quote:
Originally Posted by Icon
Of course this means you will have to have an efficient copy constructor which like your constructor leaves the memory uninitialized.

Well, I have tried it but it will break the reliability of the code. For example reallocation depends on copy constructor. So after the reallocation the memory was uninitialized with all values lost. The only way how get this working would be to enhance copy constructor to detect uninitialised matrix and in such case it will not copy the contents of matrix but will just allocate memory. This is apparently simplest solution.

Quote:
Originally Posted by Icon
All of this can also be accomplished using resize()

Well, this one was my first attempt It fails also:

error: no instance of constructor "matrix<mp_real>::matrix" matches the argument list
resize(size_type __new_size, value_type __x = value_type())
^
detected during instantiation of "void std::vector<_Tp, _Alloc>::resize(size_t={unsigned long}, _Tp) [with _Tp=matrix<mp_real>, _Alloc=std::allocator<matrix<mp_real>>]"

So we have come to the conclusion that for efficient implementation I will rewrite copy constructor to detect uninitialized matrix and instead of copying the data it will just allocate memory and leave it uninitialized. It's definitely better solution than trying to create new Allocator class.

Thanks a lot!
Jiri

Reply With Quote
  #13  
Old January 30th, 2009, 05:42 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
The compiler is telling you the same thing as with the constructor:
Code:
resize(size_type __new_size, value_type __x = value_type())

this means that resize will resize the vector to __new_size size and the elements will be initialised with __x. If you dont specify __x (of type value_type, i.e., your element type), like in a.resize(10) then the default parameter will be used, which in this case is the default constructed element, ie, value_type().

But as with the ctor you can specify the initial value of the elements by doing
resize( 10, matrix<mp_real>(1000,1000) )

Of course in the end this is the same as the solution with the constructor. (Even worse possibly if you dont call reserve(10) first). I guess you'll have to fix up your copyconstructor.

Your objects basically have 2 states, where normal objects only have one. I mean: when I write a class I try to make the constructor initialise an object completely. If the constructor completes the object is valid and fully usable. If it does not complete then you dont have an object. In your case when the ctor finishes you have this 'intermediary-uninitialised' state. Which in the end is not that bad but complicates things.

Reply With Quote
  #14  
Old January 30th, 2009, 06:12 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Quote:
Originally Posted by Icon
The compiler is telling you the same thing as with the constructor:
Code:
resize(size_type __new_size, value_type __x = value_type())

this means that resize will resize the vector to __new_size size and the elements will be initialised with __x. If you dont specify __x (of type value_type, i.e., your element type), like in a.resize(10) then the default parameter will be used, which in this case is the default constructed element, ie, value_type().

But as with the ctor you can specify the initial value of the elements by doing
resize( 10, matrix<mp_real>(1000,1000) )

Of course in the end this is the same as the solution with the constructor. (Even worse possibly if you dont call reserve(10) first). I guess you'll have to fix up your copyconstructor.

Your objects basically have 2 states, where normal objects only have one. I mean: when I write a class I try to make the constructor initialise an object completely. If the constructor completes the object is valid and fully usable. If it does not complete then you dont have an object. In your case when the ctor finishes you have this 'intermediary-uninitialised' state. Which in the end is not that bad but complicates things.


Hi,

Quote:
Originally Posted by Icon
Of course in the end this is the same as the solution with the constructor. (Even worse possibly if you dont call reserve(10) first). I guess you'll have to fix up your copyconstructor.

Yes, exactly. It's the same as the solution with the constructor.
static vector < matrix<mp_real> > > b(10,matrix<mp_real>(1000,1000) );

And without reserve it will grow like this 1->2->4->8->16 copying the values many times.

Quote:
Originally Posted by Icon
Your objects basically have 2 states, where normal objects only have one. I mean: when I write a class I try to make the constructor initialise an object completely. If the constructor completes the object is valid and fully usable.

I don't think that this is really problem. Of course I could initilizate the matrix to some value (like 0) but it's just not necessary. And if I would do this than copyconstructor will have to copy the values all the time. So quick copy (= just allocate the memory if source matrix was not initialised) would be not possible. IMHO, the real problem is here that constructor needs arguments (size of the matrix). And there is no easy way how to pass these arguments to Vector class

Thanks!
Jiri

Reply With Quote
  #15  
Old January 31st, 2009, 07:51 AM
MaHuJa's Avatar
MaHuJa MaHuJa is offline
Contributing User
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Dec 2007
Posts: 1,177 MaHuJa User rank is Private First Class (20 - 50 Reputation Level)MaHuJa User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 21 h 27 m 36 sec
Reputation Power: 12
Send a message via Skype to MaHuJa Send a message via XFire to MaHuJa
If the speed of this copy is really such a problem, how about using a singleton-like wrapper object?

Code:
struct matrix {
	matrix(int a, int b) {}
};

class matwrap { 
	matrix* data;
	int sizea;
	int sizeb;
public:
	matwrap(int a, int b) : data(0), sizea(a),sizeb(b) {};
	~matwrap() { delete data; }
	matrix* operator-> () {
		if (!data) data = new matrix(sizea,sizeb);
		return data;
	}
};
This does mean writing an extra -> whenever you use the objects (which isn't free computationally either), but your initialization time is reduced by not having to copy those... 80 Mb?


-------


This problem is one that is solved in C++0x.
The solution is called rvalue references (&& where a reference would usually use &).

According to http://wiki.apache.org/stdcxx/C++0xCompilerSupport only gcc and Visual C++ 10 (which is only available as a "Community Technology Preview") supports this yet - though there are more compilers around, I don't know of any that have gotten further.

What you *could* do, if you were so inclined, is to get a compiler that supports rvalue references, and create a "move" constructor. The idea is that a move constructor is allowed to ruin the original object, so you could write
vec.pushback(move(matrix(1000,1000)))
to have it only allocate once for each object. Move is a function located in namespace std, which inlines to a noop, but lets the compiler know you want to "move" rather than "copy" the object. This means to allow a "destructive copy", which ruins the original, is allowed - such as merely taking over the pointers to the allocated arrays. (Make sure the original's destructor won't invalidate yourself though.)

It does assume that the vector::push_back() function has been overloaded to take rvalue references, but using the standard library that follows the compiler will probably ensure that.

Last edited by MaHuJa : January 31st, 2009 at 07:55 AM.

Reply With Quote
  #16  
Old February 2nd, 2009, 05:13 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Quote:
Originally Posted by MaHuJa
If the speed of this copy is really such a problem, how about using a singleton-like wrapper object?

Code:
Hi MaHuJa,

this is what I have tried. I have built a vector of pointers.

matrix<mp_real>* aa;
vector <  matrix<mp_real>* > pb;
for (int k=0; k<90; ++k) {
	aa=new matrix<mp_real>(length_of_sum,2*range+1);
	pb.push_back(aa);
	for(int i=0; i < length_of_sum; ++i) {
		for (int j=0; j< 2*range+1; ++j) {
			pb[k]->elem(i,j) =  mp_real(double(j-range)) +  mp_real(i);
		}
	}
}
cout << "Done." << endl;
cout << pb[0]->operator()(100,5) << endl; 


The drawback of this is that matrices can be scaterred over the memory. So I have decided not to use it but stay with the normal vector (which will copy the data).


Quote:
Originally Posted by MaHuJa
This problem is one that is solved in C++0x.
The solution is called rvalue references (&& where a reference would usually use &).

Only gcc and Visual C++ 10 (which is only available as a "Community Technology Preview") supports this yet - though there are more compilers around, I don't know of any that have gotten further.

What you *could* do, if you were so inclined, is to get a compiler that supports rvalue references, and create a "move" constructor. The idea is that a move constructor is allowed to ruin the original object, so you could write
vec.pushback(move(matrix(1000,1000)))
to have it only allocate once for each object. Move is a function located in namespace std, which inlines to a noop, but lets the compiler know you want to "move" rather than "copy" the object. This means to allow a "destructive copy", which ruins the original, is allowed - such as merely taking over the pointers to the allocated arrays. (Make sure the original's destructor won't invalidate yourself though.)

It does assume that the vector:ush_back() function has been overloaded to take rvalue references, but using the standard library that follows the compiler will probably ensure that.

Very interesting! But how does move actually behaves when used with vector:ush_back() function? Vector class will ensure that all members are in thecontinous memory. So if the move does nothing but only create link (like using pointers) than it will break this continous memory. So I assume that vec.pushback(move(matrix(1000,1000))) will at the end COPY the data to make sure that all vector members are in the continous memory segment.

I believe that if you want to use Vector class and avoid copy then you have to create new Allocator class. Currently there is no way how to simply tell to Vector class it should use constructor with parameters.

Jiri

Reply With Quote
  #17  
Old February 2nd, 2009, 05:32 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Sep 2005
Posts: 1,021 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 2 Weeks 8 h 12 m 36 sec
Reputation Power: 14
I don't think an allocator solves your problems. I must admit I have never (had to use) used them but afaik they are for allocating memory from a different place then the global heap. But I may very well be wrong on this account.

Nevertheless, even though your matrix objects will be contiguous in memory because of the vector, the elements member variable of a matrix object is not contiguous with other elements member variables of other objects. So the singleton-wrapper (which looks more like a pimpl/proxy to me) does not cost you more than just an extra indirection.

So move will _not_ copy the data (i.e., your elements member variable) because that data does not need to be contiguous in memory. What will happen with rvalue references is that instead of a full-blown copy construct call, a 'smarter' move constructor is called, which might prevent some copying.

Reply With Quote
  #18  
Old February 2nd, 2009, 06:42 AM
MaHuJa's Avatar
MaHuJa MaHuJa is offline
Contributing User
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Dec 2007
Posts: 1,177 MaHuJa User rank is Private First Class (20 - 50 Reputation Level)MaHuJa User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 21 h 27 m 36 sec
Reputation Power: 12
Send a message via Skype to MaHuJa Send a message via XFire to MaHuJa
Quote:
Originally Posted by Jirka77
The drawback of this is that matrices can be scaterred over the memory. So I have decided not to use it but stay with the normal vector (which will copy the data).

First of all, the matrix data itself is already scattered in memory, as the matrix template uses a pointer to it. (Otherwise, the size would have been part of the template parameters, not a constructor parameter.)

There are, however, two drawbacks to your code above.
1) It introduces an extra indirection - and one visible to the programmer, at that. (Read: the programmer has an extra chance to mess up)
2) The vector does not automatically destruct the matrixes when it goes out of scope, this needs to be done manually.


Quote:
Very interesting! But how does move actually behaves when used with vector::push_back() function? Vector class will ensure that all members are in thecontinous memory. So if the move does nothing but only create link (like using pointers) than it will break this continous memory. So I assume that vec.pushback(move(matrix(1000,1000))) will at the end COPY the data to make sure that all vector members are in the continous memory segment.

Code:
struct str {
	char* a;
	str() { a=0; }
	~str() { delete a; } // Noop if zero, after all
	str(const str& orig) { // Copy constructor
		a=new char[strlen(orig.a)];
		strcpy (a,orig.a);
	}
	str(str&& orig) { // Move constructor - C++0x feature, not C++03.
		a=orig.a;
		orig.a=0;	// Invalidates original
	}
}

Presuming that vector<T> has been properly implemented to use rvalue references (which is a pretty safe assumption);
vector<T>::pushback() has been overloaded with (T&&), which will invoke the move constructor rather than the copy constructor which is used now. And if the vector, due to growth, has to reallocate, it will move construct each contained object rather than copy construct. Which means that it usually doesn't need to copy the children.

In the absense of a move constructor, it will use a copy constructor. Such as the default one.

std::move()'s function in all of this is to make sure the rvalue version of the function (&&) is run even if the expression itself yields an lvalue.

----

Also, take a look at std::deque<T> - it's a middle ground between vector and list. Think of it like a list node holding a number of entries, not just one. When you exceed the number you are holding space for, it allocates a new block, and puts the overshooting objects into that.

If you don't need the "all objects in one big array" property of the vector class, in other words if you don't do
void foo(T*,int count);
vector<T> v;
foo(&v[0], v.size());

then deque can give the same functionality at surprisingly marginal performance costs.

Reply With Quote
  #19  
Old February 2nd, 2009, 11:20 AM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Quote:
Originally Posted by Icon
I don't think an allocator solves your problems. I must admit I have never (had to use) used them but afaik they are for allocating memory from a different place then the global heap. But I may very well be wrong on this account.

Well, the idea was to use Allocator to pass the size of matrix to Vector class. This way I could force Vector to call constructor matrix(sizea,sizeb). But it's too much work.


Quote:
Originally Posted by Icon
Nevertheless, even though your matrix objects will be contiguous in memory because of the vector, the elements member variable of a matrix object is not contiguous with other elements member variables of other objects.

Yes, you are right. So we agree that using pointers to matrices is fine.

Quote:
Originally Posted by Icon
So the singleton-wrapper (which looks more like a pimpl/proxy to me) does not cost you more than just an extra indirection.

Well, I can build a vector of pointers to matrices (See my code above). However, I don't see how can I use matwrap to build a vector - please notice that matwrap constructor takes two arguments as input. So again, I cannot use
vector <matwrap> b(10);

I can only do
vector <matwrap> b;
matwrap m<100,100);
m(i,j)=func(i,j);
b.push_back(b);

And b[0]->(i,j) can be used to access the data.

OK, when I think about it it's more elegant that my vector of pointers.

Quote:
Originally Posted by MaHuJa
There are, however, two drawbacks to your code above.
1) It introduces an extra indirection - and one visible to the programmer, at that. (Read: the programmer has an extra chance to mess up)

I agree that my code is more messy. However, I don't see any extra indirection. In my code:
pb[0]->operator()(100,5):
1) pb[0] pointer to matrix is found in Vector
2) matrix at memory location pb[0] is taken

In your code:
b[0]->(i,j):
1)b[0] pointer to matwrap is found in memory
2)operator->() will found address of matrix
3)i,j element of matrix at memory location b[0]::data is taken

So there is one more level of indirection in your code. But I agree that your code is more elegant.

Quote:
Originally Posted by MaHuJa
2) The vector does not automatically destruct the matrixes when it goes out of scope, this needs to be done manually.

Agreed.

Quote:
Originally Posted by Icon
So move will _not_ copy the data (i.e., your elements member variable) because that data does not need to be contiguous in memory. What will happen with rvalue references is that instead of a full-blown copy construct call, a 'smarter' move constructor is called, which might prevent some copying.

Agreed. It will copy the pointers but data itself will stay at place.

Thanks a lot for your comments. The C++0x move operator is completely new to me and it's very nice feature, indeed! So along to find the best solution to this problem (which seems to be matwrap, followed by vector of pointers to matrices and followed by the vector of matrices (perhaps with improved copy constructor) ) I have learned something new!

Jiri

Reply With Quote
  #20  
Old February 2nd, 2009, 12:41 PM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Hi MaHuJa,

so I have tried your code:

C++ Code:
Original - C++ Code
  1. class matwrap {
  2.             matrix<mp_real>* data;
  3.             int sizea;
  4.             int sizeb;
  5.         public:
  6.             inline matwrap(int a, int b) : sizea(a),sizeb(b),data(NULL) {}
  7.             inline int init(){
  8.                 data = new matrix <mp_real> (sizea,sizeb);
  9.                 return 0;
  10.             }
  11.             ~matwrap() { cout << "des" << endl; delete data; }
  12.             inline mp_real &operator() (int i, int j) const {
  13.                     return data->elem(i,j);
  14.             }
  15.         };


It's not working. I do

C++ Code:
Original - C++ Code
  1. for (unsigned int k=0; k < length_of_a; ++k){
  2. a_divided.push_back(matwrap(length_of_sum,2*range+  1));
  3. a_divided[k].init();
  4. a_divided[k](i,j) =


It works fine as long as the size of an array a_divided.reserve(length_of_a) is big enough. However, when Vector class calls reallocate, it will copy the data and call desctructor of matwrap afterwards. This will delete the data itself because only pointers has been copied.

Since i do not have version of the compiler which supports MOVE i have to write also copy function for class matwrap to copy the data itself correctly.

Thanks
Jiri

Reply With Quote
  #21  
Old February 2nd, 2009, 01:02 PM
Jirka77 Jirka77 is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Jan 2009
Posts: 8 Jirka77 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 57 m 4 sec
Reputation Power: 0
Hi MaHuJa,

after some thinking I reverted back to my code. In your code, copy function is needed which will in fact really COPY the data. ( I don't have C++0x compiler). I have reverted back to my code

C++ Code:
Original - C++ Code
  1. matrix<mp_real>* aa;
  2. vector <  matrix<mp_real>* > pb;
  3. for (int k=0; k<90; ++k) {
  4.     aa=new matrix<mp_real>(length_of_sum,2*range+1);
  5.     pb.push_back(aa);
  6.     for(int i=0; i < length_of_sum; ++i) {
  7.         for (int j=0; j< 2*range+1; ++j) {
  8.             pb[k]->elem(i,j) =  mp_real(double(j-range)) +  mp_real(i);
  9.         }
  10.     }
  11. }
  12. cout << "Done." << endl;
  13. cout << pb[0]->operator()(100,5) << endl; 

which does not need to really copy the data.

You are right that when vector vanishes, it will not delete the data automatically. So I need to take care about this when calling destructor of the class where vector of pointers to matrices is used.

I believe that to achive the same functionality - no need to copy the data itself I would have to remove delete data; from ~matwrap().

Thanks
Jiri

Reply With Quote
  #22  
Old February 3rd, 2009, 05:19 AM
MaHuJa's Avatar
MaHuJa MaHuJa is offline
Contributing User
Dev Articles Beginner (1000 - 1499 posts)
 
Join Date: Dec 2007
Posts: 1,177 MaHuJa User rank is Private First Class (20 - 50 Reputation Level)MaHuJa User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 21 h 27 m 36 sec
Reputation Power: 12
Send a message via Skype to MaHuJa Send a message via XFire to MaHuJa
I overlooked the vector relocation part completely right then. My bad.

----

Take a look at std::deque. Its inner workings can roughly be described as a linked list of arrays; such that instead of allocating a new array and moving all data over there, it allocates a new array and keeps the overshooting elements in that new array.

And when it comes to reading it, benchmarks showed surprisingly little impact. YMMV though.

----

Also, just came to mind, shared_ptr<>, which was included in the C++ standard as of tr1. You might find it under std::tr1::shared_ptr if your implementation has updated for tr1 (Visual C++ 2008 service packed it in, afaik) and it will be std::shared_ptr for C++0x. If your compiler doesn't have this yet, it's part of the boost libraries, and you can probably get only the header file for shared_ptr for inclusion in your project if that's more to your liking. The boost version is called boost::shared_ptr.

shared_ptr<X> will work exactly the same as X* except for automatically deleting when the last pointer is gone. This makes it well suited for vector.

Reply With Quote
Reply

Viewing: Dev Articles Community ForumsProgrammingC/C++ Help > Classes - How to pass arguments to constructor when using Vector(STL)?


Developer Shed Advertisers and Affiliates


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

© 2003-2018 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap