By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,109 Members | 969 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,109 IT Pros & Developers. It's quick & easy.

vectors - push_back() method

P: 33
Hello,

suppose I have a string temp that I want to push in a vector vec1, using:
Expand|Select|Wrap|Line Numbers
  1.    vec1.pushback(temp);
  2.  
I noticed that if I change the content of temp, it will change the content of vec1[lastItem], unless I push in another value after temp. Another variant to get vec1 immunized against changes in temp was to use
Expand|Select|Wrap|Line Numbers
  1.    vec1.pushback(temp.c_str());
  2.  
vec1 is declared like vector<string> vec1.

pushback() awaits for a variable of type "const string&", so should I understand that the last element in the vector always points to another variable, and that only when a new value is pushed that the last value gets copied to a new location? What about the glitch with c_str()?
Borland's 5 help thinness kills me...

Your thoughts on this would be appreciated,

Ras.
Jun 19 '07 #1
Share this Question
Share on Google+
7 Replies


weaknessforcats
Expert Mod 5K+
P: 9,197
This code using Visual Studio.NET 2005 does not reproduce your problem.
Expand|Select|Wrap|Line Numbers
  1. vector<string> v;
  2. string temp("Hello");
  3. v.push_back(temp);
  4. vector<string>::iterator itr = v.begin();
  5. while (itr != v.end())
  6. {
  7.    cout << *itr << endl;
  8.    ++itr;
  9. }
  10. temp = "world!";
  11. v.push_back(temp); //vector not changed if this commented out
  12. itr = v.begin();
  13. while (itr != v.end())
  14. {
  15.    cout << *itr << endl;
  16.    ++itr;
  17. }
  18.  
Are you sure don't have a vector<string&>?

C++ requires a vector be implemented as an array forcing the container to make a copy of the object placed in the container so it would be a major bug in the template if that were not true.
Jun 19 '07 #2

P: 33
Thanks for taking the time to test and answer.
Are you sure don't have a vector<string&>?
Sure. I didn't even know this type of declaration was permitted. What's the applications?


C++ requires a vector be implemented as an array forcing the container to make a copy of the object placed in the container so it would be a major bug in the template if that were not true.
I tested your code on my compiler, and it did not produce the unexpected behaviour. It seems it's because of the nature of the modification you applied to temp.

In my code I had something like:
Expand|Select|Wrap|Line Numbers
  1. vector<string> v;
  2. string temp("Say \"Hello\"");
  3. v.push_back(temp);      // If I replace temp by temp.c_str(), the problem does not occur
  4. vector<string>::iterator itr = v.begin();
  5. while (itr != v.end())
  6. {
  7.    std::cout << *itr << std::endl;
  8.    ++itr;
  9. }
  10. std::strtok((char*)temp.c_str(),"\"");   // Here I modify the contents of temp, ONLY. I use the char* cast and c_str() to fit the function requirements.
  11. itr = v.begin();
  12. while (itr != v.end())
  13. {
  14.    std::cout << *itr << srd::endl; // KA-BOUM: Instead of 'Say "hello"', only 'Say' is displayed.
  15.    ++itr;
  16. }
  17.  
And THIS produces the unexpected behaviour. Notice that strtok() should affect only temp.

Would you have the kindness to test this on your compiler? Or if you noticed anything in this code to point it out to me?

Thanks,

Ras.
Jun 20 '07 #3

weaknessforcats
Expert Mod 5K+
P: 9,197
Thanks for taking the time to test and answer.
Quote:
Originally Posted by
Are you sure don't have a vector<string&>?


Sure. I didn't even know this type of declaration was permitted. What's the applications?
You are correct here. I guess I got carried away. Usually, I compile my code examples. Obviously, this time I did not. Good catch.

std::strtok((char*)temp.c_str(),"\""); // Here I modify the contents of temp, ONLY. I use the char* cast and c_str() to fit the function requirements.
This won't work. The string::c_str() method produces the contents of the string objuect as a non-modifyable C-string. Your cast cause the compiler to make a copy that is non-const. You are changing that copy.

There is no reason to believe the string object is a C-string. Almost certainly it is not.

Lastly, I ran your code with Visual Studio.NET and I do not see the unexpected behavior. I see:

Expand|Select|Wrap|Line Numbers
  1. Say "Hello"
  2. Say "Hello"
  3.  
Jun 20 '07 #4

P: 33
Thanks for your time.

Good catch.
This is the learner's job!


This won't work. The string::c_str() method produces the contents of the string objuect as a non-modifyable C-string. Your cast cause the compiler to make a copy that is non-const. You are changing that copy.
Well, in the help of my compiler I see that the declaration of strtok() is
Expand|Select|Wrap|Line Numbers
  1. char *strtok(char *s1, const char *s2)
  2.  
Furthermore, an example is given;
Expand|Select|Wrap|Line Numbers
  1.  int main(void)
  2.  {
  3.     char input[16] = "abc,d";
  4.     char *p;
  5.  
  6.     /* strtok places a NULL terminator
  7.     in front of the token, if found */
  8.     p = strtok(input, ",");
  9.     if (p)   printf("%s\n", p);
  10.  
  11.     /* A second call to strtok using a NULL
  12.     as the first parameter returns a pointer
  13.     to the character following the token  */
  14.     p = strtok(NULL, ",");
  15.     if (p)   printf("%s\n", p);
  16.     return 0;
  17.  }
  18.  
So this effectively changes the contents of s1. As for c_str(), I need it because I actually don't use std::cout for output, but the method ShowMessage(const AnsiString msg). In Borland this function pops-up a simple dialog box with the contents of msg, which must be of type Ansistring. c_str() allows me to go from string to AnsiString. I do agree temp is not changed.

For the outputs, I certify that using Borland 5.0 we get:
Expand|Select|Wrap|Line Numbers
  1. Say "Hello"
  2. Say
  3.  
What strikes me is that the value of temp is already pushed in the stak. Normally whatever would happen to temp should not reflect out there.

Finally, I did not understand this:
There is no reason to believe the string object is a C-string. Almost certainly it is not.


Ras.
Jun 21 '07 #5

weaknessforcats
Expert Mod 5K+
P: 9,197
Finally, I did not understand this:
Quote:
Originally Posted by
There is no reason to believe the string object is a C-string. Almost certainly it is not.
A C-string is a char array with the last element a null terminator.

It is an assumption that the string uses this format. For example, using the templates with Visual Studio.NET. sizeof string is 32. That's a lot bigger than a struct with a char* in it. Also, there is no reason for a null termnator as the string length could be managed by a size member.

I knoe of one STL implementation that uses a 28 byte char array and a char*. The reasoning was that most strings are 28 bytes or less. More than that and the array is not used and the char* takes over to mahange the data on the heap.

All that's known for sure is that c_str() converts the string object to a non-modifyable C-string.

Maybe the Borland templates use a C-string. Maybe the Borland templates are not C++ compliant so that c_str() let you chnage the string object.

There are at least 8 STL implementation that I know of and most of the containers are implemented differently.

The fact that you get this behavior with the Borland templates tells me that they may be older templates and that there may be newer templatws with bug fixes.

For sure, though, in C++, you should not be using the C string library (strtok, strlen, strcmp, etc...).
Jun 21 '07 #6

P: 33
Thanks. And to finalize this dicussion, what are the options that replace:
the C string library (strtok, strlen, strcmp, etc...).

Ras.
Jun 22 '07 #7

weaknessforcats
Expert Mod 5K+
P: 9,197
Thanks. And to finalize this dicussion, what are the options that replace:
Quote:
Originally Posted by weaknessforcats
the C string library (strtok, strlen, strcmp, etc...).
strtok is replaced by the various find algorithms of the STL.
strlen is string::size()
strcmp is string::compare() (Note the string::operator== just calls string::compare

Just check out the member functions for basic_string<>. string is just basic_string<char>.
Jun 22 '07 #8

Post your reply

Sign in to post your reply or Sign up for a free account.