Multi-dimensional Vector Pointer - c++

I have the following multi-dimensional vector
int main()
{
vector< vector<string> > tempVec;
someFunction(&tempVec);
}
void someFunction(vector< vector<string> > *temp)
{
//this does not work
temp[0]->push_back("hello");
}
How do i push data into the vector when i have a vector pointer?
The below code does not work.
temp[0]->push_back("hello");

You need
(*temp)[0].push_back("hello")
That's:
dereference temp to get a vector<vector<string> > &
get first element, a vector<string> &
use . instead of -> because you're no longer handling pointers
That said, it would be easier if someFunction took a vector< vector<string> >& instead of a pointer: temp[0].push_back("hello"). References do not allow pointer arithmetic or null pointers, so they make it harder to screw up and are more suggestive of the actual kind of input required (a single vector, not an optional one or an array of them).

Related

Making an array of pairs of vectors

I'm trying to make an array of pairs of vectors, and in the vectors is another pair of int and float. Here is the code to help explain: pair<vector<pair<int,float> >, vector<float> >[numNodes];
At first I just had an array of a vector of pairs, but now that I changed it to an array of pairs I'm being thrown errors. I think the errors have to do with the placement of make_pair but I'm not sure.
Here is my code, but first, I little more information on what exactly I'm trying to do with the code. I'm working on a school assignment where the goal is to read in a three files of a graph and store it as an adjacency matrix and adjacency list. Right now I'm working on the list. One file has just the connections, another has the weights of the connections, and the last file has the position values of each node. Then I will search the graphs with different search algorithms. The array of vectors was the adjacency list and all the other data types involved in the pair<vector<pair<int,float> >, vector<float> >[numNodes]; were an attempt to store these variables in the list. I know another way of doing this would be to have a Node object with member variables where I can save the nodeID and position values, but I don't know exactly how this would work in terms of adding it into the list. Also would there be advantages to doing this rather than having everything stored in the list?
class AdjacencyList{
public:
pair<vector<pair<int,float> >, vector<float> > *adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weight)), posVals);
}
}
And here is the error I'm being thrown:
main.cpp:71:39: error: no member named 'push_back' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weig...
Another Error I'm getting after changing the array of vectors to an array of pairs is this:
no member named 'size' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
return adjList->size();
This size function was working before the change, which makes me think these errors are happening because its recognizing it as a pair now instead of an array. Any ideas on how to fix this?
I have no idea what vector of pairs of vectors of pairs of ints and floats and vectors of floats could possibly in any possible way represent, but anyway you could just assign to the pairs of vectors you want to assign to:
#include <vector>
class AdjacencyList{
public:
std::vector<
std::pair<
std::vector<std::pair<int,float>>,
std::vector<float>
>
> adjList;
int numNodes;
AdjacencyList(int numNodes) :
numNodes(numNodes),
// construct the vector with numNodes default-constructred elements
adjList(numNodes) {
}
void addEdge(int sourceNode, int destNode, float weight, std::vector<float> posVals){
// prefer at() instead of [] for error checking
adjList.at(sourceNode) = std::make_pair(
std::vector<std::pair<int, float>>{
// vector of pairs?? anyway:
std::make_pair(
destNode, weight
)
},
posVals
);
}
};
Do not use raw pointers - use std::vector for managing dynamic array. Your code leaks memory allocated by new.
In the first error thrown, the compiler is complaining about a missing method push_back being called. If you look at it, this makes sense because you are trying to call push_back from a pair variable (which does not have implemented any push_back method). And a similar thing goes with the second error: size() is a valid method for the vector class, but here you are calling it from a pointer pointing to an array (check this question for more info).
Instead of an array of pairs, you could use a vector of pairs, or even a set of pairs:
class AdjacencyList{
public:
vector<pair<vector<pair<int,float> >, vector<float> > > adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
// no need to initialize the vector
//adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
// add the new pair <int, float> to the existent vector for this source node
adjList[sourceNode].first.push_back(make_pair(destNode, weight));
// define second value of the outer pair as the parameter variable posVals?
adjList[sourceNode].second = posVals;
// or you wanted to do this? I don't think so :S
make_pair(adjList[sourceNode].first, posVals);
}
}
You could do the same using an outer set instead of vector, and then you would need to change the push_back(...) for insert(...), so that you obtain the benefits of sets of pairs as well.
Actually, if you need to do it using outer arrays, then your code would be fine but changing your AddEdge function to the one proposed above.
I don't really know which is the desired performance of the code, but if you provide more information about it I might be able to help a bit more.
I think you have some inconsistencies in the type declared and the type being added.
You have declared an array (now does not matter whether it is an array, vector, or set) of pairs of vectors. Whereas on your addEdge function you are creating a pair of None (push_back returns None) and vector. The push_back on its side is adding the pair <int, float> of the first vector of the outer pair to you differently variable defined above.

Inserting shared pointers to strings from cin into vector

I am trying to insert shared pointers to strings into a vector using the copy algorithm. Is it possible to read lines from the istream and store shared_ptr's to those strings in a vector using the copy algorithm? So far I'm stuck with the following class.
class DVector
{
typedef vector<shared_ptr<string>> PTSVector;
PTSVector data;
public:
void push_back()
{
copy(istream_iterator<string>(cin),
istream_iterator<string>(),
back_inserter(data));
}
};
Can anyone tell me what might go wrong?
Thanks!
std::copy isn't appropriate here, because you're reading strings, but trying to store pointers to strings.
Your source and destination types are different, so you need std::transform, instead. This function is similar to copy, but it applies a function to transform the input before writing it to the output iterator.
transform(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(data),
[](const string& str) { return make_shared<string>(str); });

Strings in Vectors. and placing them in order

So I am placing objects in a vector. I want to drop them in order as they are added. the basics of the object are
class myObj {
private:
string firstName;
string lastName;
public:
string getFirst;
string getLast;
}
I also have a vector of these objects
vector< myObj > myVect;
vector< myObj >::iterator myVectit = myVect.begin();
when I add a new object to the vector I want to find where it should be placed before inserting it. Can I search a vector by an object value and how? This is my first attempt
void addanObj (myObj & objtoAdd){
int lowwerB = lower_bound(
myVect.begin().getLast(), myVect.end().getLast(), objtoAdd.getLast()
);
int upperB = upper_bound(
myVect.begin().getLast(), myVect.end().getLast(), objtoAdd.getLast()
);
from there i plan to use lowwerB and upper B to determine where to insert the entry. what do I need to do to get this to work or what is a better method of tackling this challenge?
----Follow up----
the error I get when I attempt to compile
error C2440: 'initializing' : cannot convert from 'std::string' to 'int'
No user-defined-conversion operator available that can perform this conversion,
or the operator cannot be called
The compiler highlights both lower_bound and upper_bound. I would guess it is referring to where I am putting
objtoAdd.getLast()
-----More Follow up-----------------
THis is close to compiling but not quite. What should I expect to get from lower_bound and upper_bound? It doesnt match the iterator i defined and im not sure what I should expect.
void addMyObj(myObj myObjtoadd)
vector< myObj>::iterator tempLB;
vector< myObj>::iterator tempUB;
myVectit= theDex.begin();
tempLB = lower_bound(
myVect.begin()->getLast(), myVect.end()->getLast(), myObjtoadd.getLast()
);
tempUB = upper_bound(
myVect.begin()->getLast(), myVect.end()->getLast(), myObjtoadd.getLast()
);
Your calls to std::lower_bound and std::upper_bound are incorrect. The first two parameters must be iterators that define a range of elements to search and the returned values are also iterators.
Since these algorithms compare the container elements to the third parameter value you'll also need to provide correct operator< functions that compare an object's lastName and a std::string. I've added two different compare functions since std::lower_bound and std::upper_bound pass the parameters in opposite order.
I think I have the machinery correct in this code, it should be close enough for you to get the idea.
class myObj {
private:
std::string firstName;
std::string lastName;
public:
std::string getFirst() const { return firstName; }
std::string getLast() const { return lastName; }
};
bool operator<(const myObj &obj, const std::string &value) // used by lower_bound()
{
return obj.getLast() < value;
}
bool operator<(const std::string &value, const myObj &obj) // used by upper_bound()
{
return value < obj.getLast();
}
int main()
{
std::vector<myObj> myVect;
std::vector<myObj>::iterator tempLB, tempUB;
myObj objtoAdd;
tempLB = std::lower_bound(myVect.begin(), myVect.end(), objtoAdd.getLast());
tempUB = std::upper_bound(myVect.begin(), myVect.end(), objtoAdd.getLast());
}
So this is definitely not the best way to go. Here's why:
Vector Size
A default vector starts out with 0 elements, but capacity to hold some number; say 100. After you add the 101st element, it has to completely recreate the vector, copy over all the data, and then delete the old memory. This copying can become expensive, if done enough.
Inserting into a vector
This is going to be even more of a problem. Because a vector is just a contiguous block of memory with objects stored in insert order, say you have the below:
[xxxxxxxzzzzzzzz ]
if you want to add 'y', it belongs between x and z, right? this means you need to move all the z's over 1 place. But because you are reusing the same block of memory, you need to do it one at a time.
[xxxxxxxzzzzzzz z ]
[xxxxxxxzzzzzz zz ]
[xxxxxxxzzzzz zzz ]
...
[xxxxxxx zzzzzzzz ]
[xxxxxxxyzzzzzzzz ]
(the spaces are for clarity - previous value isn't explicitly cleared)
As you can see, this is a lot of steps to make room for your 'y', and will be very very slow for large data sets.
A better solution
As others have mentioned, std::set sounds like it's more appropriate for your needs. std::set will automatically order all inserted elements (using a tree data structure for much faster insertion), and allows you to find particular data members by last name also in log(n) time. It does this by using bool myObj::operator(const & _myObj) const to know how to sort the different objects. If you simply define this operator to compare this->lastName < _myObj.lastName, you can simply insert into the set much quicker.
Alternately, if you really really want to use vector: instead of sorting it as you go, just add all the items to the vector, and then perform std::sort to sort them after all the inserts are done. This will also complete in n log(n) time, but should be considerably faster than the current approach because of the vector insertion problem.

std::map keys in C++

I have a requirement to create two different maps in C++. The Key is of type CHAR* and the Value is a pointer to a struct. I am filling 2 maps with these pairs, in separate iterations. After creating both maps I need find all such instances in which the value of the string referenced by the CHAR* are same.
For this I am using the following code :
typedef struct _STRUCTTYPE
{
..
} STRUCTTYPE, *PSTRUCTTYPE;
typedef pair <CHAR *,PSTRUCTTYPE> kvpair;
..
CHAR *xyz;
PSTRUCTTYPE abc;
// after filling the information;
Map.insert (kvpair(xyz,abc));
// the above is repeated x times for the first map, and y times for the second map.
// after both are filled out;
std::map<CHAR *, PSTRUCTTYPE>::iterator Iter,findIter;
for (Iter=iteratedMap->begin();Iter!=iteratedMap->end();mapIterator++)
{
char *key = Iter->first;
printf("%s\n",key);
findIter=otherMap->find(key);
//printf("%u",findIter->second);
if (findIter!=otherMap->end())
{
printf("Match!\n");
}
}
The above code does not show any match, although the list of keys in both maps show obvious matches. My understanding is that the equals operator for CHAR * just equates the memory address of the pointers.
My question is, what should i do to alter the equals operator for this type of key or could I use a different datatype for the string?
My understanding is that the equals operator for CHAR* just equates the memory address of the pointers.
Your understanding is correct.
The easiest thing to do would be to use std::string as the key. That way you get comparisons for the actual string value working without much effort:
std::map<std::string, PSTRUCTTYPE> m;
PSTRUCTTYPE s = bar();
m.insert(std::make_pair("foo", s));
if(m.find("foo") != m.end()) {
// works now
}
Note that you might leak memory for your structs if you don't always delete them manually. If you can't store by value, consider using smart pointers instead.
Depending on your usecase, you don't have to neccessarily store pointers to the structs:
std::map<std::string, STRUCTTYPE> m;
m.insert(std::make_pair("foo", STRUCTTYPE(whatever)));
A final note: typedefing structs the way you are doing it is a C-ism, in C++ the following is sufficient:
typedef struct STRUCTTYPE {
// ...
} *PSTRUCTTYPE;
If you use std::string instead of char * there are more convenient comparison functions you can use. Also, instead of writing your own key matching code, you can use the STL set_intersection algorithm (see here for more details) to find the shared elements in two sorted containers (std::map is of course sorted). Here is an example
typedef map<std::string, STRUCTTYPE *> ExampleMap;
ExampleMap inputMap1, inputMap2, matchedMap;
// Insert elements to input maps
inputMap1.insert(...);
// Put common elements of inputMap1 and inputMap2 into matchedMap
std::set_intersection(inputMap1.begin(), inputMap1.end(), inputMap2.begin(), inputMap2.end(), matchedMap.begin());
for(ExampleMap::iterator iter = matchedMap.begin(); iter != matchedMap.end(); ++iter)
{
// Do things with matched elements
std::cout << iter->first << endl;
}

Function returning an iterator of vector

I have this new class Seq that inherits vector and has some additional features. I can use all methods of vector with Seq.
Having this data structure:
Seq< vector<int> > sweepEvents;
I want to have a function that takes an element vector edge search for it in sweepEvents and returns the iterator to the position of the found element in sweepEvents (if and only if edge is found) and the iterator to the last elements of the vector (if and only if edge is not found).
Then I want to work with this iterator, in that I want to compare the elements from the prev and the next position of iterator.
I have the following function for founding and returning the iterator:
Seq< vector<int> >::iterator QSweep::insertSweepEvents(edge_t edge,int currentDim){
int changePosition;
int found=0;
for (int i=0;i<currentDim;i++){
if (edge[0]==sweepEvents[i][1]){
changePosition=i;
found=1;
return sweepEvents.begin()+changePosition;
}
}
if (found==1){
sweepEvents.rep().insert(sweepEvents.begin()+changePosition,edge);
sweepEvents.rep().erase(sweepEvents.begin()+changePosition+1);
}
else{
sweepEvents.rep().insert(sweepEvents.end(),edge);
}
return sweepEvents.end()-1;
}
I then call this iterator in the main function. I actually tried but it does not compile and I do not know what syntax to use other than this:
int main(){
Seq< vector<int> > sweepEvents;
vector<int> edge;
//.....initialize sweepEvents and edge
//declare iterator but not working
Seq< vector<int> >::iterator comparePosition;
//not working neither
comparePosition=insertSweepEvents(edge,sweepEvents.size());
}
Any idea on how I should correctly call the iterator? I see it does not work as an integer index from an array?
Is Seq< vector< T > >::iterator defined in your Seq class?
Making the parameter of the template 'vector' does not imply that exists the type Seq< vector< int > >::iterator
What compilation error ? How is defined Seq<X>::iterator ?
#include <vector>
template<typename T>
struct Seq
: public std::vector<T>
{ };
typedef Seq< std::vector<int> > SeqI;
SeqI::iterator insertSweepEvents(SeqI &s)
{
return s.begin();
}
int main()
{
SeqI s;
SeqI::iterator e = insertSweepEvents(s);
}
This works fine.
Something illogical in your code. See my comments:
int found = 0;
for (int i=0;i<currentDim;i++){
if (edge[0]==sweepEvents[i][1]){
changePosition=i;
found=1;
// This place is one, where we assign 1 to found, and we do return after that (maybe you want do break/?)
return sweepEvents.begin()+changePosition;
}
}
if (found==1){ // as you see we reach this place only when found == 0
A little sidenote:
After a vector is changed, especially when appended to or inserted in, iterators to it become invalid. That's due to the fact that the vector tries to allocate a minimally sized contiguous block of memory for it's internal data, while at the same time it tries to minimize the number of times it needs to allocate a new, bigger chunk. So the data may move through memory, so iterators to it before a push are no longer valid after it.
Another little note:
You can find the difference between two iterators by using std::difference( it1, it2 ). You can re-apply that difference by using std::advance( it1, d ).
A third little note:
You seem to have a 'return' statement inside the for-loop, but the rest of the code uses variables that are set only when returning...