4

In a recent question, I learned that there are situations where you just gotta pass a char* instead of a std::string. I really like string, and for situations where I just need to pass an immutable string, it works fine to use .c_str(). The way I see it, it's a good idea to take advantage of the string class for its ease of manipulation. However, for functions that require an input, I end up doing something like this:

std::string str;
char* cstr = new char[500]; // I figure dynamic allocation is a good idea just
getstr(cstr);               // in case I want the user to input the limit or
str = cstr;                 // something. Not sure if it matters.
delete[] cstr;
printw(str.c_str());

Obviously, this isn't so, uh, straightforward. Now, I'm pretty new to C++ so I can't really see the forest for the trees. In a situation like this, where every input is going to have to get converted to a C string and back to take advantage of string's helpful methods, is it just a better idea to man up and get used to C-style string manipulation? Is this kind of constant back-and-forth conversion too stupid to deal with?

Community
  • 1
  • 1
Maulrus
  • 1,787
  • 2
  • 17
  • 27

2 Answers2

3

In the example you give, you can generally read a line into a std::string using the std::getline function: http://www.cplusplus.com/reference/string/getline/

Of course this doesn't do everything that a curses library does. If you need a non-const char* so that some C function can read into it, you can use a vector<char>. You can create a vector<char> from a string, and vice-versa:

std::string       a("hello, world");
std::vector<char> b(a.begin(), a.end());

// if we want a string consisting of every byte in the vector
std::string       c(b.begin(), b.end());

// if we want a string only up to a NUL terminator in the vector
b.push_back(0);
std::string       d(&b[0]);

So your example becomes:

std::vector<char> cstr(500);
getnstr(&cstr[0], 500);
printw(&cstr[0]);
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • I've been told not to mix input/output from different sources (in this case, iostreams and curses) - is that not true? Also, as far as I'm aware, a `vector` can't grow as the function reads into it, because these functions expect fixed-length `char` arrays; so is there any real advantage to using a `vector`? – Maulrus Nov 03 '10 at 02:10
  • 1
    @Maulrus: Yes, it's true. If you can't get by with iostreams, and you need curses, then use the second strategy. The advantage of using vector is that you don't have to free anything to avoid memory leaks. To a C programmer that might not seem like much, but try writing some C++ code where some of the functions that you call can throw exceptions, and you'll soon see why it's a bad idea to hold any resource that must be explicitly freed. For that matter, even without exceptions it's nice not to have cleanup code in every function you write. – Steve Jessop Nov 03 '10 at 02:12
  • I see. So using `vector` is the same as `char*` as far as the function is concerned, but with some of C++'s added safety? – Maulrus Nov 03 '10 at 02:14
  • 1
    @Maulrus: yes, that's right. Since we're ignoring the fact that `vector` can be re-sized and so on, what it's providing us is a managed array of `char`. If you would have put a `char` array on the stack, maybe then `vector` isn't bringing anything to the party any more. The only caveat, really, is *possible* performance differences - my `vector` above initializes all its elements to `0`, which is unnecessary in this case. But (a) premature optimization and all that, and (b) zeroing out a few hundred bytes of memory is likely negligible compared with reading from a terminal. – Steve Jessop Nov 03 '10 at 02:17
  • So, for personal clarification: your recommendation would be to use the `vector` as a substitute for `char*`, copying it to a `string` when (if?) I need any `string`-based methods? – Maulrus Nov 03 '10 at 02:20
  • 1
    @Maulrus: Yes, `vector` as a substitute for dynamically-allocated char arrays. – Steve Jessop Nov 03 '10 at 02:22
1

Most std::string::c_str() implementations (if not all of them) simply return a pointer to an internal buffer. No overhead whatsoever.

Beware however that c_str() returns a const char*, not a char*. And that the pointer will become invalid after the function call. So you cannot use it if the function does anything like writing back into the passed string or makes a copy of the pointer.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536