still struggling with vectors

Pages: 12
Hi, all –

I have an object that contains a vector of values. I need to pass certain locations in the vector to a routine that will assign values to that portion of the vector.

When I was doing this with arrays, it looked like this:
readDataFile (s, NBR_COEFFS_BW, &(modHostValues[MOD_BWC00]));

Where NBR_COEFFS_BW was the number of array elements to assign to, and MOD_BWC00 provided the index to the starting location.

I've defined the routine as follows:

long readDataFile(string file, long nbrCells, std::vector<SocReg>& a)

So, my question is...can I still do pass a starting address with vectors? And if so, how do I code it? And if not, what might be a better alternative?

Thanks.
I'd add an extra parameter to your readDataFile function:
long readDataFile(string file, long nbrCells, std::vector<SocReg>& a, int start_index)
Or whatever you want to call it. I don't know how your routine works internally, but to loop over the locations you wanted to write to, you could just do:
1
2
3
4
for ( int i = start_index; i < start_index + nbrCells; ++i )
{
    a[i] = // etc.
} // for 

You don't need to worry about horrible pointers and addresses and stuff with vectors - that's all hidden away in the implementation.
Hope that helps.
Thanks for the reply. Your solution seems effective, though sort of low-tech (for lack of a better word). Is it really difficult to pass a pointer to the section of the vector where I want to start?

I do appreciate the help.
Hi @mzimmers
Your solution seems effective, though sort of low-tech (for lack of a better word).

Well, you need to remember that a std::vector is a class with a public interface and a private implementation that's hidden from the user (http://cplusplus.com/reference/stl/vector/).
Very different from a C-style array. You can't just slice it in half and pass a pointer to the last bit, any more than you could do that with a 'Car_engine' or a 'Database_connection' class object. You need to work through that interface. In the case you highlighted above, I think the best way would just be to pack the whole thing off by reference together with a 'start' index.
But I'll happily stand corrected if anyone's got a better method ;)
Regards, keineahnung
closed account (zb0S216C)
mzimmers wrote:
So, my question is...can I still do pass a starting address with vectors? And if so, how do I code it? And if not, what might be a better alternative? (sic)

Your question isn't quite clear enough to receive an effective response. Are you trying to say that you want to pass the base address of a vector to a function?

Wazzak
&v.front()

Not too much thought has gone into the code snippet above so I doubt it's what you asked for. You're welcome.
Hi, keineahnung –

That's a very good explanation; I now understand why what I was trying to do won't work. Thank you.

To Framework: no, I was trying to pass the address of the middle of a vector to a function, but based on keineahnung's explanation, that no longer appears viable.

This does seem like a pretty big limitation of the vector, though, which leads me to believe I'm probably trying to use it improperly. Let me explain what I was trying to do with a little more detail: I wanted to create a class with a fairly large array/vector of elements, many of which are series (for example, elements 21:30 might be a sub-list of ten values), and I was hoping to pass the start of that series to a routine. This class has several "clients" who would receive the location of such a series. Pretty straightforward with an array, but evidently less so with a vector.

I suppose that I don't absolutely need to use a vector, but it was my understanding that I should try to use vectors instead of arrays in C++, so that's what I was trying to do. Should I perhaps abandon this effort and just go with arrays?
OK, as the day progresses, I'm realizing more and more, that I know less and less about vectors.

Here's a bit from an include file I'm working on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const	long	MOD_RES_NBR_CELLS = 9;
const	long	MOD_RES_NBR_BANKS = 128;
const	long	MOD_RES_FINAL_CELL = MOD_RES_NBR_CELLS - 1;
const	long	MOD_RES_COEFF_REGS = MOD_RES_NBR_CELLS + 2;

// class definition.

class ModResamp
{
	std::vector<CellFeedback>	cellsI;
	std::vector<CellFeedback>	cellsQ;
	Gain   	gain;
	std::vector<SocReg>	coeffs;
	std::vector<SocReg>coeffTable;

public:
	ModResamp(long rv = 0);			// default constructor 


And here's the constructor:

1
2
3
4
5
6
ModResamp::ModResamp(long rv)    // default constructor
	: cellsI(MOD_RES_NBR_CELLS, CellFeedback(rv)),
	  cellsQ(MOD_RES_NBR_CELLS, CellFeedback(rv)),
	  gain(rv),
	  coeffs(MOD_RES_COEFF_REGS, rv),
	  coeffTable(MOD_RES_NBR_CELLS * MOD_RES_NBR_BANKS, 0)


Based on this, could I not expect the constructor to give me a vector called "cellsI" of MOD_RES_COEFF_REGS elements of type CellFeedback, and to initialize those cells pursuant to their own constructors?

Because...that's not happening. At least the initialization isn't working right. (It's tough working with vectors in the debugger because they don't display as cleanly as arrays do, but my final elements at least aren't initializing.)

Thanks.
Hi
Sorry not got much time to look at this at the moment (- work! ) but...
and to initialize those cells pursuant to their own constructors?

No it'll just allocate the memory. EXCEPT because you can resize them dynamically (vectors, that is) you don't really need to set the size initially. I normally use something like:

1
2
3
4
5
6
7
8
std::vector<My_class_type> vec;
for ( int i = 0; i < n; ++i )
{
    // create object on stack
    My_class_type mct( /* whatever */ );
    // copy it into vector
    vec.push_back( mct );
} // for 


I suppose you could combine that into one step if you wanted:
vec.push_back( My_class_type( /* ... */ ) );

I sort of know what you mean (I think) about the limitations and 'low-tech' thing, but I'd suggest it's mostly illusory and based on the preconceptions you're bringing to the table from your experience with C. If you're on an IBM 386 there might be some performance gain from arrays but on a modern PC vectors are blisteringly fast and offer a much safer and more flexible way of doing things. And once you start using them in the wider context of STL (all the alogrithms and stuff) I think you'll start to see the advantages. You've definitely made the right decision to ditch arrays :)
Regards, keineahnung


Thanks for taking the time to look more at this. I want to pursue something about the constructor, though: each element in my vector is itself an object of type CellFeedback, which in turn is made of 5 other objects. Are you telling me that my code above is NOT going to initialize each object? It seems to at least be initializing the first one, but as I mentioned, looking at vectors in the debugger is tough. All I know is, it's not doing all of them.

If this isn't working as I thought, I need to know how I do go about initializing all the contents of the CellFeedback objects (all of them).

Whenever you get a chance to reply, that would be great. Thanks.
For your original question, pass an iterator. Instead of


long readDataFile(string file, long nbrCells, std::vector<SocReg>& a)

use


long readDataFile(string file, long nbrCells, std::vector<SocReg>itetator iter)

and call the function like so:

readDataFile( s, NBR_COEFFS_BW, a.begin() + MOD_BWC00 )
Doh!
Ignore that last post of mine - shouldn't write when I'm in a rush ;)
Of course you can initialize objects on vector creation! I had some other thing in my head for some reason.
A quick example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
#include <vector>
#include <boost/foreach.hpp>

class A
{
    private:
        int x;
    public:
        A( int xx = 3 ): x(xx) {}
        void display() { std::cout << x << "\n"; }
}; // class A
 
int main()
{
    std::vector<A> vec( 4, A() );
    BOOST_FOREACH ( A a, vec )
    { 
        a.display();
    } // BOOST_FOREACH

    return 0;

} // main 


That'll create 4 objects of class A with the default constructor.

Last edited on
So...can anyone see anything wrong with my code above? I was told in another thread that this should work. I've got a fairly deep nesting of objects in my program: about five or six levels. The "rv" argument gets passed through to the bottom, where it's supposed to set an integer in the final object.

But, while my debugger isn't showing me much information on the vectors, it's pretty clear that the initialization isn't working right. I need to solve this before I get back to my fun with vectors.

I'm not expecting anyone to solve this for me, but...can you see anything patently incorrect in my code?

Thanks.
Alrededor -

A belated thank you for pointing out iterators to me. So, in the example above, can I merely use "iter" in a loop and increment it arithmetically?

EDIT:

Evidently, I can't. So, where my for loop looked like this before:

for (int i=startIndex; i < nbrCells + startIndex; i++)

What should it look like now?

Thanks.

EDIT 2:

So, I've played around with it a little, and this seems to work:

1
2
		for (int i = 0; i < nbrCells; i++)
			s >> *iter++;


Can someone please tell me whether it looks like I'm handling the iterator correctly here? I'd like someone's stamp of approval before I consider this solved.

Thanks.
Last edited on
Since the postfix increment operator ++ has a higher precedence than the dereferencing operator *, in the line:

s >> *iter++;

the postfix increment operator binds to the iterator and not to the value stored in *iter. Thus the output from s becomes the value which is stored in *iter and then since it is postfix, the iterator is incremented.

Your line: for (int i=startIndex; i < nbrCells + startIndex; i++)

could be written with iterators as:

1
2
3
4
5
6
7
8
std::vector< int > a;
// populate the vector a

for( std::vector< int >iterator iter = a.begin() + startIndex;  iter != a.begin() + startIndex + nbrCells; ++iter );
{
   // whatever you want in the body of the loop
   s >> *iter;
}


or as a while loop:

1
2
3
4
5
6
7
8
9
std::vector< int > a;
// populate the vector a

std::vector< int >iterator iter = a.begin() + startIndex;
while( iter != a.begin() + startIndex + nbrCells );
{
   // whatever you want in the body of the loop
   s >> *iter++;
}


This would go through the loop nbrCells times. I would note that the line s >> *iter++; could also be written:

s >> *iter;
iter++;

or

s >> *iter;
++iter;

both of which may be a little clearer since you don't have to remember the precedence of the two operators.

Hi, Alrededor -

Is there an advantage to using an iterator in the for loop above? Or, is it simply good practice to use them whenever dealing with vectors?

Thanks.
There's no point to passing an iterator instead of the vector...

Your fault (in the first post) was that you were trying to pass-by-reference the first element of the vector. That's useless, as it has "no meaning". Just pass it as such, without the index:

1
2
3
4
void func_taking_vector(vector<int> &myVecByRef) {}
...
vector<int> myVec = ...
func_taking_vector(myVec);


Now, you can use the vector as if it is present inside the scope of that function [because it is, sort of].
You DO need an index if you're passing a single vector of a multi-dimensional vector, as such:

1
2
3
4
void func_taking_vector(vector<int> &myVecByRef) {}
...
vector<vector<int>> my2DVec; // Vector "matrix"
func_taking_vector(my2DVec[5]); // Passes the 6th "row" (or column, depending on how you look at it) 

Hope that makes sense.
Hi, Gaminic –

Thanks for the reply. I don't think your suggestion gets me all the way home, though. I need to be able to pass a starting point within the vector (not the start of the vector itself) into the routine.

The iterator method Alrededor suggested seems to be working; here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
long	readDataFile(string file,
				   long nbrCells,
				   vector<SocReg>::iterator iter)
{
	int		rc;
	ifstream    s(file.c_str());

	if (s)
	{
		for (int i = 0; i < nbrCells; i++)
			s >> *iter++;
		rc = 0;
	}
	else
	{
		cout << "Cannot open " << file << "." << endl;
		rc = 1;
	}
	s.close();
	return rc;


And I call it like this:

1
2
	s = "coeffs/coeffmodyquist.txt";
	readDataFile (s, NBR_COEFFS_NYQ, modHostValues.begin() + MOD_NYQC00);


To derive the desired offset into the vector.

I haven't tested it to death, but preliminary results are successful.
I'm sorry, I think I misread.

Is the goal to overwrite a part of the vector? e.g. "Starting from element E, overwrite the next N values"? If so, it's probably still easiest to pass the vector by reference, as well as a starting point (int) and count or end (int).

Iterators work, but they're fishy with vectors, because they can become invalid after certain operations (e.g. adding or erasing elements). I find it much easier to work with direct access ([] operator). Aside from being "always valid" (if you manually adjust the index after add/delete operations), they also make debugging much, much easier. But that's just my personal preference, so it's your pick of course.
You probably didn't misread; more likely I just wasn't clear.

Yes, I have one long vector that I need to populate. Various sections of the vector get filled by various files. That's why I was trying to pass a vector offset into the read routine, but I discovered that vectors don't work that way.

I believe I have it working now, but I welcome any further comments about "best of practices" and form...
Pages: 12