views:

172

answers:

4

I know how to add integers to strings, but I'm not sure I'm doing it in an efficient matters. I have a class where I often have to return a string plus an integer (a different integer each time), in Java I would do something like

public class MyClass {
  final static String S = "MYSTRING";
  private int id = 0;

  public String getString() {
    return S + (id++);
  }
}

But in C++ I have to do;

class MyClass {
 private:
  std::string S; // For some reason I can't do const std::string S = "MYSTRING";
  int id;

 public:
  MyClass() {
    S = "MYSTRING";
    id = 0;
  }

  std::string getString() {
    std::ostringstream oss;
    oss << S << id++;
    return oss.str();
  }
}

An additional constraint: I don't want (in fact, in can't) use Boost or any other librairies, I'll have to work with the standard library.

So the thing is; the code works, but in C++ I have to create a bunch of ostringstream objects, so it seems inefficient. To be fair, perhaps Java do the same and I just don't notice it, I say it's inefficient mostly because I know very little about strings.

Is there a more efficient way to do this ?

A: 

You are right, ostringstream generally add overhead.

This is more efficient, and IMO is more idiomatic...

std::string adder() {
    static int i;
    char buf[32];
    snprintf(buf, sizeof(buf), "MYSTRING%i", i++);
    return buf;
}
kotlinski
Very C-like, I'll take a look at it, thanks.
Shinka
Note that, as written, this will not return the desired result if `i`'s string representation is more than seven characters long. Maybe that's fine for your purposes, but it points to one of the reasons to prefer `stringstream` over the C-like techniques.
Kristopher Johnson
+3  A: 

I'm pretty sure you can do the following:

class MyClass 
{
 private:
  const std::string S; // For some reason I can't do const std::string S = "MYSTRING";
  int id;

 public:
  MyClass() :
     S( "MYSTRING" )
  {
    id = 0;
  }
}

Thats totally off the top of my head and untested though so I'm fully expecting tonnes of down votes :D hehehe

Goz
You *can* do this, but why do it? This will end up copying MYSTRING into every object of class MyClass, when you probably want a static const string that is the same single copy for every MyClass object.
Zan Lynx
@Zan: Functionally, this is identical to the C++ code Shinka provided, except that `S` is `const`. He's answering the wrong question, but this is the right way to do what he expressed a desire to do.
Dennis Zickefoose
+6  A: 

std::ostringstream is the "standard" way to do this in C++. You might be able to make something more efficient via some custom coding, or laboriously comparing the performance of ostringstream, itoa, and sprintf on all the systems where you'll be deploying this program, but it's probably not worth the effort.

I'd say the real problem with the std::ostringstream solution is not about efficiency. The real problem is that the code just looks too complicated.

I know you don't want to use Boost, but if you look at Herb Sutter's The String Formatters of Manor Farm, you could just copy the (very tiny) definition of the lexical_cast<>() template into your program. Then your code would look like this:

std::string getString() {
    return S + lexical_cast<std::string>(id++);
}

Whether this is more efficient than your existing solution depends on a lot of factors (how well your compiler inlines template instantiations, for example), but it definitely looks cleaner.

Kristopher Johnson
+2  A: 

To add to the other answers:

... the code works, but in C++ I have to create a bunch of ostringstream objects, so it seems inefficient. To be fair, perhaps Java do the same and I just don't notice it, ...

Java does in fact do exactly the same thing; + with Strings is syntactic sugar for StringBuffer.append(), so these do the same thing:

String f = "foo";
f += "bar" + "baz";

String f = "foo";
f = StringBuffer(f).append("bar").append("baz");
Michael Mrozek