C++/Regarding vector of vectors
Expert: Ralph McArdell - 9/10/2007
QuestionHi,
Please look at the following code:
dependencies(int i)
{
string str;
vector<string> fd;
cout<<"enter the attributes of fd"<<i<<endl;
cin>>str;
fd.push_back(str);
}
int _tmain(int argc, _TCHAR* argv[])
{
int num;
cout<<"Enter the number of functionaldependencies"<<endl;
cin>>num;
for(int i=0; i<num; i++)
{
dependencies(i);
}
}
In the above code I am calling the function "dependencies" depending on the given input for number of functional dependencies. In the "dependencies" function, whatever i am inputting is pushed into the vector. But everytime I call the function, the input that I give gets into the same vector.
But what i want to do is, everytime I call the function dependencies, it should create a new vector and push that iteration inputs into new vector instead of pushing into the same old vector.
Is it possible to do that way??
Please help!!
Thanks!!
AnswerI suggest you start by revising the behaviour of local automatic objects (variables) in C++.
What you describe you want is in fact happening. It is not however doing it in a way that you probably want.
Every time you make a function call _all_ local automatic objects (those created on the stack frame of the function call) in that function are created. When the function is left - whether normally via a return statement (or end of the function if the return type is void) or via a C++ exception the objects are destroyed and their destructors are called.
Thus the life time of such objects is at most the duration of the function call.
Hence every time you call the dependencies function a new vector is created, has a single string appended to it and is destroyed (along with the string object str and the copy pushed back to the vector - that is C++ standard library containers delete all their contained items when they are destroyed and make copies of the elements they are asked to hold, rather than holding references to the original item).
Further I note that you do not explicitly state the return type of the dependencies function, you declare it like so:
dependencies(int i)
This is illegal C++ - in C you are allowed to do this and an int return type is assumed - so even if this were the case the function is still mal-formed as it returns no value. For example MSVC++ 8.0 (a.k.a. 2005) gives the following error when I pasted you function in to a convenient source file:
main.cpp(152) : error C4430: missing type specifier - int assumed.
Note: C++ does not support default-int
In C++ you _must_ explicitly state the return type of functions, and in both C and C++ if a function returns no value (i.e. it is a procedure) then it should explicitly state a void return type:
void dependencies(int i)
I also note from your use of the non-standard _tmain and _TCHAR that you are probably using a Microsoft compiler or one that supports at least some MS C/C++ specific features. Note that some MS compilers - the older ones in particular - are not all that standard in their understanding of C++.
So maybe fd was supposed to be a local static object, such that its life time is from the first call of dependencies to the end of the program? Or maybe you are trying to return a vector to the caller (this does not seem to be the case in the code you show)?
Assuming the static local object case, as this seems nearer to you existing code, you just left off the static qualifier to the declaration of fd, you could have many vectors by having a collection of vectors, for example a vector of vectors:
static std::vector< std::vector<std::string> > vfd;
vfd.push_back( std::vector<string>() );
// ...
vfd.back().push_back( str );
Here I define a vector that contains as elements vectors of std::string objects. This is a local static object so will be created on the first call (and only on the first call) to dependencies and exists until the program terminates - i.e. it exists between function calls. I call this vfd - for vector of fd.
Each time dependencies is called a new vector of strings is appended to vfd. I then modify the way in which the string entered is appended to a vector. I select the last vector of string in vfd (i.e. the one just added) using vfd.back() and call push_back on this vector of strings to append the string to it.
I suspect that what you would really require is that the value i is associated with a particular vector of strings. In this case we can modify our example like so:
string str;
static std::vector< std::vector<std::string> > vfd;
if ( vfd.size() <= i )
{
vfd.resize(i+1);
}
// ...
vfd[i].push_back( str );
Here I again create vfd as before. However this time we check to see if we have enough vectors based on the value of i. If the size of vfd (the number of vector of strings it contains) is less than or equal to the value of i then we need to resize the vector to accommodate the extra size. The check for this is if i is zero then we need at least 1 item in vfd - thus we need to resize vfd to 1 (or greater) - which is 0 + 1 or i + 1. Note that resize may copy the exiting data in the vector elsewhere (as more memory may be required) and the new item(s) are created using their default constructor, which is all OK for our requirements. We could prevent too many initial resizes by pre-allocating enough space for a few vector of string elements when vfd is created:
static std::vector< std::vector<std::string> > vfd(5);
Note in the above variant that I have passed a value of 5 to initialise vfd with. This effectively resizes vfd to 5 elements before we start. However whether this is really much of a performance saver is debatable as std::vector types perform such tricks themselves internally to ensure they do not have to re-allocate memory and copy the contents more than necessary.
I cannot see much point to the pieces of code you show - so must assume you are only showing fragments of the whole code to demonstrate your point. I would still ask: what are you really trying to achieve? I ask as you may be better solutions. For example - use a class that contains a string, or std::vector<std::string> as appropriate then have main (or _tmain) hold a vector of objects of this class type. The class could have instance member functions to operate on individual strings or string vectors.