• Advertisement
Sign in to follow this  

integer list with std::string like behaviour

This topic is 4793 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

std::strings are so easy to use and you never have to care about memory allocation. I've been trying to use std::vectors for lists of integers, but for some reason I find them hard to use and they give me random crashes :( with an std::string you can do something like:
std::string s;
//s is now ""
s = "abcde";
//s is now "abcde"
s += 'f';
//s is now "abcdef"
s.insert(2, 'B')
//s is now "abBcdef"
s.erase(2, 1);
//s is now again "abcdef"
s[0] = 'A';
//s is now "Abcdef"
int i = s.length();
//i now contains the number of characters in s
I'd like to be able to do all these things with a list of integers, like this:
std::AlienThing a = {1, 2, 3, 4};
//s is now {1, 2, 3, 4}
a += 5;
//a is now {1, 2, 3, 4, 5}
//one extra element inserted
//no thinking about memory allocation or out of bounds required
//I want to be able to keep doing this forever without ever allocating anything
a.insert(2, 7);
//a is now {1, 2, 7, 3, 4, 5}
//a 7 inserted at location two, the other elements are translated to the right
//no thinking about memory allocation or out of bounds required
a.erase(2, 1);
//a is now again {1, 2, 3, 4, 5}
a[0] = 0;
//a is now {0, 2, 3, 4, 5}
int i = a.length();
//i now contains number of elements in a, which is 5
How do I do this? with what type of thing? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Quote:

I've been trying to use std::vectors for lists of integers, but for some reason I find them hard to use and they give me random crashes :(


Well std::vector is exactly what you want. What problems are you having with it?

To implement your examples:


std::vector < int> vec;

vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);

vec.push_back(5);

vec.insert(vec.begin() + 2, 7);

vec.erase(vec.begin() + 2);

vec[0] = 0;



Alan

Share this post


Link to post
Share on other sites
Well, I'm not entirely sure how std::string ( I think it's simply an embellished char * ) is implemented, but you could make a wrapper around an int *, and dynamically allocate an array of ints, overload the =, +=, etc operators, and possibly make the [] operator bounds-checking.

I should think you would do it like an std::vector, where you have a size and a capacity, size being the number of elements in the array, and capacity being the size of the array. Once size == capacity, you double the capacity using realloc or some similar function.

erase( unsigned index, unsigned length ) would shift elements [length] to the left from position [index + length] till [size], making the necessary bounds-checks.

insert( unsigned index, const int &element ) would shift elements one to the right from [index] and replace array[index] with element.

size() just returns the private data member describing size;

This is all off the top of my head, so it may not be entirely right. It's how I would do it though...

Regards,
jflanglois

[edit] And then there is always Alan Kemp's suggestion, which would be easier to implement, and ends up being the same thing under the hood... Stupid me.

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
Well, I'm not entirely sure how std::string ( I think it's simply an embellished char * ) is implemented


its not as simple as that, most implemenations of std::basic_string (this is not required) make std::basic_string nothing more than a smart handle to a reference counted private repsentation with COW (copy-on-write) schematics this is of-course can be bad in multi-threaded enviroments.

@Lode if you really want something like this then you might want to look into boost's assignement library either use or observe how you can achieve this effect with-out having to introduce new user-defined types, how-ever its strongly suggested not to be used as you could imagine it causing confusion to say team members using your code, here is a simple example of what can be achieved with boost's assignement library:


vector<int> v;
v += 1,2,3,4,5,6,7,8,9;

Share this post


Link to post
Share on other sites
Quote:
So if using push_back() etc. is not your bag, then you could just create a basic_string<int> and voila. :)

Nice, Zahlman. :D, could even typedef it an istring...

snk_kid, do you have a reference for that information? What you said did not quite help me (through no fault of your own, to be sure) -- I have no idea what Copy-On-Write Schematics are.

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
snk_kid, do you have a reference for that information? What you said did not quite help me (through no fault of your own, to be sure) -- I have no idea what Copy-On-Write Schematics are.


if you read these 3 good articles (not that long) on GotW:

Reference Counting - Part I.
Reference Counting - Part II
Reference Counting - Part III

All will be revealed and make more sense, it even use an example custom string type that shows how to implement it.

actually the last one is optional but recommended read as it talks about COW limitations in certain contexts.

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
Quote:
So if using push_back() etc. is not your bag, then you could just create a basic_string<int> and voila. :)

Nice, Zahlman. :D, could even typedef it an istring...


Although as nice as this may be this will most likely bork in certain sisutions, doing this is also non-portable code, why? because std::basic_string has another type parameter char traits which defaults to std::char_traits that currently you must do a specialization for your char types (that is if you use std::char_traits for the character traits type) if you don't then it will default to char_traits<int> with the generic code which will most likely be implementated (if at all) different on each compiler this is non-portable.

[Edited by - snk_kid on January 5, 2005 5:14:14 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
if you read these 3 good articles (not that long) on GotW:

Reference Counting - Part I.
Reference Counting - Part II
Reference Counting - Part III

All will be revealed and make more sense, it even use an example custom string type that shows how to implement it.

actually the last one is optional but recommended read as it talks about COW limitations in certain contexts.

That's quite interesting. Here's my question, though: are many implementations, that use COW, of std::basic_string (and the STL in general) not thread-safe?

Quote:
Original post by snk_kid
Although as nice as this may be this will most likely bork in certain sisutions, doing this is also non-portable code, why? because std::basic_string has another type parameter char traits which defaults to std::char_traits that currently you must do a specialization for your char types (that is if you use std::char_traits for the character traits type) if you don't then it will default to char_traits<int> with the generic code which will most likely be implementated (if at all) different on each compiler this is non-portable.

Right, I see. So it would seem that sticking with std::vector or a custom implementation is best for the OP.

Anyway, rating++ for the illumination.

Share this post


Link to post
Share on other sites
Yo,

I tried with std::vectors again, and it kinda works like I want, except for some strange behaviour:

I have a class with a std::vector<int> in it.

If I now make two different objects of the class, the second one does weird. If I don't make the first one, the second one does normal. Is it possible that the std::vector<int>'s of both objects are actually influencing each other?

Do std::vectors's get automaticly destroyed, or do they create some alien effects after you used an object containing one of them?

EDIT: problem fixed: I was accidently reading a value out of bounds from a std::vector, and it returned a value left over from the other object. Darn such things are hard to debug! ;)

[Edited by - Lode on January 5, 2005 4:23:20 PM]

Share this post


Link to post
Share on other sites
Helpful Tip: always use .at() , unless it is really time-critical. And it will be much simpler to debug :-). (even if time-critical, usually .at() overhead is small enough)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement