Generating a Unique (numbered) Name in C++

Started by
16 comments, last by M2tM 15 years, 3 months ago
I'm trying to replicate a simple piece of code in C++ which was written in a Basic variant. Essentially, I start out with a name, which can be anything. I then check in an associative array to see if the name is already used. If it's not, I use it. If it is, I add a number to the end of the name until I end up with a unique name. So if I tried to create an object called "Item" 5 times, I would end up with "Item", "Item1", "Item2", "Item3" and "Item4" respectively. I do this with a simple integer increment and then convert the integer to a string, and concatenate. C++ doesn't make converting from int to string particularly easy. I'm wondering what the most elegant way of doing this is. I'm currently leaning towards writing a class for it. Create an instance of the class, then call the increment method which, internally, uses a char array and a simple loop to cycle the digits through all the permutations. But by God that seems like a messy and bloated way of doing what should be a simple procedure. Is there a cleaner, neater way to do this?
Advertisement
It sounds like representing names in your map as strings is causing you undue stress. Why can't a name be a struct consisting of a string and an int? Once you have that (plus a suitable less-than operator), finding the highest-numbered item with a given string-part would be as easy as a std::upper_bound.
Quote:Original post by sybixsus
Is there a cleaner, neater way to do this?
There most certainly is.

From the least to the most preferable:
a) Using std::stringstream from the C++ standard library.
b) Using boost::lexical_cast from the boost library.

I'm too tired to trust myself to give you bug free examples of them all but a quick bit of searching reveals that MaulingMonkey has serendipitously handled them before!

Edit: After sweeping the sleep away from my eyes I see that MaulingMonkey's examples are actually of the complete reverse problem (strings -> integers), I'll leave it as an exercise for you to figure out how to swap them around [grin]

[Edited by - dmatter on January 10, 2009 11:08:43 PM]
Quote:C++ doesn't make converting from int to string particularly easy. I'm wondering what the most elegant way of doing this is.


What is so difficult about:

#include <sstream>...int val = 10;    // integer valuestd::string str; // stringstd::stringstream buf;buf << val;str = buf.str();
Quote:Original post by sybixsus
I'm trying to replicate a simple piece of code in C++ which was written in a Basic variant. Essentially, I start out with a name, which can be anything. I then check in an associative array to see if the name is already used. If it's not, I use it. If it is, I add a number to the end of the name until I end up with a unique name.

So if I tried to create an object called "Item" 5 times, I would end up with "Item", "Item1", "Item2", "Item3" and "Item4" respectively. I do this with a simple integer increment and then convert the integer to a string, and concatenate. C++ doesn't make converting from int to string particularly easy. I'm wondering what the most elegant way of doing this is.

I'm currently leaning towards writing a class for it. Create an instance of the class, then call the increment method which, internally, uses a char array and a simple loop to cycle the digits through all the permutations. But by God that seems like a messy and bloated way of doing what should be a simple procedure.

Is there a cleaner, neater way to do this?


Here is the string stream method in a template function for easy conversions:
template <class out_type, class in_type>out_type cast_stream(const in_type & inValue){   std::stringstream ss;   ss << inValue;    out_type outValue;    ss >> outValue;   return outValue;}...std::string result;for(int i = 0;i < 5;i++){   result = "item" + cast_stream<std::string>(i);   ...}


You can also write your own overloads for the << and >> operators and use those in your own classes to perform conversions where it makes sense.

*edit: haha, a bit late on the draw I guess.
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
Please, please stop rewriting boost::lexical_cast (poorly).
Not everyone wants to include boost just to cast from an int to a string. bost::lexical_cast is obviously preferred if you are planning on using boost, but if you are not I don't see what's wrong with writing a basic cast function.

If you could expand on exactly what is wrong with the code I posted I would be grateful.
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
Quote:Original post by M2tM
Not everyone wants to include boost just to cast from an int to a string. bost::lexical_cast is obviously preferred if you are planning on using boost, but if you are not I don't see what's wrong with writing a basic cast function.

If you could expand on exactly what is wrong with the code I posted I would be grateful.


I too was curious. After poking around it looks like boost's lexical cast manages to perform specializations that allow it to avoid redundant allocations/copies (for example, if the input is a string, then streaming the string into the stringstream is an excessive allocation and copy; if it's an output, streaming out to string is another excessive allocation and copy). Additionally, it looks like it does error checking and exception throwing.

If there's anything else that boost's lexical cast does better, or if I've gotten any of that wrong, I'd love to know as well. The header is certainly easier for a compiler to parse than for a human: the boost lexical_cast header.
Quote:Original post by M2tM
If you could expand on exactly what is wrong with the code I posted I would be grateful.

The two biggies:
1) It doesn't handle conversions to strings when the buffer has spaces in it. Ex: if you have an ordered pair class that has a text representation of "(1, 2)", the returned string would only contain "(1,".
2) It doesn't detect error conditions such as converting the string "fred" to an int.

boost::lexical_cast also does a lot of work to avoid compiler/standard library bugs including a memory leak in MSVC 2005 (without the service pack) that your code would suffer from.
Quote:Original post by M2tM
Not everyone wants to include boost just to cast from an int to a string.
Keep in mind that you don't really have to 'include Boost' to use lexical_cast; it's header only, so all you really have to do is include a single header file (if that's what you meant by 'include Boost', then never mind, although it does seem somewhat limiting to deprive oneself of such a simple and useful tool due to not wanting to include a few headers).

I'll admit though that even with the single-header Boost libraries the include trees can be fairly deep, and maybe this is what you're objecting to. For others who might read this thread though, I just wanted to clarify that Boost is not an 'all or nothing' library, but rather a collection of individual libraries, many if not most of which are header-only and require only a single inclusion.

This topic is closed to new replies.

Advertisement