When to use std::string vs char*? [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ char* vs std::string
I'm new to C++ coming from C# but I really do like C++ much better.
I have an abstract class that defines two constant strings (not static). And I wondered if a const char* would be a better choice. I'm still getting the hang of the C++ standards, but I just figured that there really isn't any reason why I would need to use std::string in this particular case (no appending or editing the string, just writing to the console via printf).
Should I stick to std::string in every case?

Should I stick to std::string in every case?
Yes.
Except perhaps for a few edge cases where you writing a high performance multi-threaded logging lib and you really need to know when a memory allocation is going to take place, or perhaps in fiddling with individual bits in a packet header in some low level protocol/driver.
The problem is that you start with a simple char and then you need to print it, so you use printf(), then perhaps a sprintf() to parse it because std::stream would be a pain for just one int to string. And you end up with an unsafe and unmaintainable mix oc c/c++

I would stick to using std::string instead of const char*, simply because most of the built-in C++ libraries work with strings and not character arrays. std::string has a lot of built-in methods and facilities that give the programmer a lot of power when manipulating strings.

Should I stick to std::string in every case?
There are cases where std::string isn't needed and just a plain char const* will do. However you do get other functionality besides manipulation, you also get to do comparison with other strings and char arrays, and all the standard algorithms to operate on them.
I would say go with std::string by default (for members and variables), and then only change if you happen to see that is the cause of a performance drop (which it won't).

Use std::string when you need to store a value.
Use const char * when you want maximum flexibility, as almost everything can be easily converted to or from one.

This like comparing Apples to Oranges. std::string is a container class while char* is just a pointer to a character sequence.
It really all depends on what you want to do with the string.
Std::string on the other hand can give you a quick access for simple string calculation and manipulation function. Most of those are simple string manipulation functions, nothing fancy really.
So it basically depends on your needs and how your functions are declared. The only advantage for std::string over a char pointer is that it doesnt require a specific lenghth decleration.

Related

c++ best way to call function with const char* parameter type

what is the best way to call a function with the following declaration
string Extract(const char* pattern,const char* input);
i use
string str=Extract("something","input text");
is there a problem with this usage
should i use the following
char pattern[]="something";
char input[]="input";
//or use pointers with new operator and copy then free?
the both works but i like the first one but i want to know the best practice.
A literal string (e.g. "something") works just fine as a const char* argument to a function call.
The first method, i.e. passing them literally in, is usually preferable.
There are occasions though where you don't want your strings hard-coded into the text. In some ways you can say that, a bit like magic numbers, they are magic words / phrases. So you prefer to use constant identifier to store the values and pass those in instead.
This would happen often when:
1. a word has a special meaning, and is passed in many times in the code to have that meaning.
or
2. the word may be cryptic in some way and a constant identifier may be more descriptive
Unless you plain to have duplicates of the same strings, or alter those strings, I'm a fan of the first way (passing the literals directly), it means less dotting about code to find what the parameters actually are, it also means less work in passing parameters.
Seeing as this is tagged for C++, passing the literals directly allows you to easily switch the function parameters to std::string with little effort.

C++: Is it safe to move a jpeg around in memory using a std::string?

I have an external_jpeg_func() that takes jpeg data in a char array to do stuff with it. I am unable to modify this function. In order to provide it the char array, I do something like the following:
//what the funcs take as inputs
std::string my_get_jpeg();
void external_jpeg_func(const char* buf, unsigned int size);
int main ()
{
std::string myString = my_get_jpeg();
external_jpeg_func(myString.data(), myString.length() );
}
My question is: Is it safe to use a string to transport the char array around? Does jpeg (or perhaps any binary file format) be at risk of running into characters like '\0' and cause data loss?
My recommendation would be to use std::vector<char>, instead of std::string, in this case; the danger with std::string is that it provides a c_str() function and most developers assume that the contents of a std::string are NUL-terminated, even though std::string provides a size() function that can return a different value than what you would get by stopping at NUL. That said, as long as you are careful to always use the constructor that takes a size parameter, and you are careful not to pass the .c_str() to anything, then there is no problem with using a string here.
While there is no technical advantage to using a std::vector<char> over a std::string, I feel that it does a better job of communicating to other developers that the content is to be interpreted as an arbitrary byte sequence rather than NUL-terminated textual content. Therefore, I would choose the former for this added readability. That said, I have worked with plenty of code that uses std::string for storing arbitrary bytes. In fact, the C++ proto compiler generates such code (though, I should add, that I don't think this was a good choice for the readability reasons that I mentioned).
std::string does not treat null characters specially, unless you don't give it an explicit string length. So your code will work fine.
Although, in C++03, strings are technically not required to be stored in contiguous memory. Just about every std::string implementation you will find will in fact store them that way, but it is not technically required. C++11 rectifies this.
So, I would suggest you use a std::vector<char> in this case. std::string doesn't buy you anything over a std::vector<char>, and it's more explicit that this is an array of characters and not a possibly printable string.
I think it is better to use char array char[] or std::vector<char>. This is standard way to keep images. Of course, binary file may contain 0 characters.

I'm getting contradictory answers, what should I do with my code?

I am making a RPG game in C++ and DirectX.
I store all the data for the game in .txt files and read/write it using `ifstream/ofstream. this has worked well for me so far when talking about creature stats and I have a hack together for creature names but this is becoming a problem.
I can store strings in the txt file and read them but I am having trouble using them. for single words I have a hack but now I am up to the story line where characters are talking to each other it is a real problem.
I asked on gamedevelopment.stackexchange how to put text on screen and was told to use D3Dtext but that only accepts C-style strings and I can only read C++ strings from the text file. This is such a big problem now that I am willing to go back and re-factor what need sit as no progress can be made until this is sorted.
So now I have a bunch of questions and I dont know which to ask first:
I want a way to draw the letters like graphics. I was told this is what D3Dtext does but I want to implement it my self if I can I just need info on how if someone knows?
If I am to use D3Dtext like so called experts advise I have to use C-style strings. so how can I convert C-style strings to C++ strings? I have a method now but that requires the new and delete operator for every string and I can see the being a big problem as it grows in complexity?
Is there a way to read C-style strings? Maybe a replacement for ifstream. I would like to keep the txt files as I really dont want to use xml but I could change the file format if it was a viable solution?
Premature optimisation I know but I plan to use the same function for every piece of text in the game so what would be a good way of doing this in terms of speed (why I dont want new/delete for every string)?
I am happy to provide any information that would be needed to help me, just ask.
std::string mystr = "Hello World.";
mystr.c_str(); // gets a null terminated const char* C-style string
Read your file as you are currently doing then if you need to access the c strings as above.
You can convert freely between C-style strings and C++'s std::string. Just use my_cpp_string.c_str() to get the C-string representation of a C++ string, and std::string my_cpp_string(my_c_string) to initialize a new std::string from a C-style string.
2) Use the c_str() method to pass your C++ strings to D3Dtext
some_D3Dtext_function(some_text.c_str())
3 and 4 then become non-issues.

Why this sprintf statement crashing? [duplicate]

This question already has answers here:
How to read and write a STL C++ string?
(3 answers)
Closed 4 years ago.
char filebuf[256];
path current = current_path();
std::cout<<"CurrentWorking "<<current<<endl;
string _UserDir = "TTiTraceLogs";
sprintf(filebuf,"%s/%s",current,_UserDir); ///crashing here
If I format only current, then it is ok.
sprintf(filebuf,"%s",current);
Output:
CurrentWorking D:/working/eclipse_projects/sadftp/CollectTTiTraceSept10_1009_174
_higher/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/Release
In the standard sprintf() function (and the other printf()-like functions), the %s specifier doesn't work with C++ stringss; it only works with C-style strings. Try _UserDir.c_str(), which gives you a const char * that points to the internal array of the string and can therefore be used with many C functions.
If current_path() returns something that is not a (possibly const) pointer to char or unsigned char, you need to convert that value too.
Is string actually std::string? And path a boost::filesystem::path? In that case, you should know that C library functions (like sprintf and printf) don't support C++ classes like std::string. That's only natural.
What you need to do is:
sprintf(filebuf, "%s%s", current.c_str(), _UserDir.c_str());
But a more elegant solution, if you're already using C++, is to either use std::stringstream or boost::format. As a bonus won't have to mess with allocating buffers on the stack and worrying that the result might be longer than the buffer (which may lead to buffer overruns and security exploits - sprintf() is probably the culprit behind many of those...).
std::stringstream
std::stringstream filebuf;
filebuf << current_path().c_str() << _UserDir;
std::string filename = filebuf.str();
boost::format
std::string filename = "%s%s" % current_path().c_str() % _UserDir;
By the way, if you just want to concatenate directories, the 'proper' way to do that with boost::filesystem::path would be:
boost::filesystem::path fullPath = current_path() / _UserDir;
Yes, the / operator is used for adding path components. They are separated by slashes after all, aren't they?
That being said, if you still choose, against all good advice, to use the old C library functions, please, for all that's good in the world, don't use sprintf(). Use the slightly-safer snprintf(), which takes the maximum buffer size as an argument.
Some of your code is unclear (e.g., what on earth is a path type?), but it looks like you're trying to print a std::string via a C-style string formatter (sprintf %s), which is totally invalid.
Look at std::stringstream. Also, for simple concatenation, std::string provides a + operator overload. So you could be doing simply:
current + "/" + whatever
sprintf only works with char*, you cannot use it with strings. Try _UserDir.c_str() and you should be fine.
What I don't understand is why your compiler doesn't complain. You can't pass non-POD types like std::string or boost::filepath as varargs; my compiler says that this will abort at runtime, and any compiler will know here that you're passing class types to a vararg. (Formally, it's undefined behavior, but unless the compiler defines it somehow as an extention, then there's no reason for it not to at least warn.)
current is not a char* pointer, it is a path so it might lead to complication
also, sprintf can't print to string variables like you are trying to do.
How long is current_path? Maybe strlen(current_path)+strlen(_UserDir)+2 > 256.
Since _UserDir is a C++ string, you'll need to get its C string to call sprintf(), which is a C function.
sprintf(filebuf,"%s/%s",current,_UserDir.c_str()); // gets C string
Also, what is a path? If it isn't like a typedef for char*, then you can't just sprintf() that either. It may be that operator<<() is overloaded for path, which is why the std::cout works.
%s indicates a C string. You have a C++ string. You need to call .c_str()
The reason of the crash has already been explained - I can only add one piece of advice - just ditch sprintf if possible and use string streams. It will make your code better. You will not have to worry about the length of the buffer or other errors like the one you encountered.

Does std::string use string interning?

I'm especially interested of windows, mingw.
Thanks.
Update:
First, I thought everyone is familiar with string interning.
http://en.wikipedia.org/wiki/String_interning
Second, my problem is in detail:
I knocked up a string class for practice. Nothing fancy you know, i just store the size and a char * in a class.
I use memcpy for the assignment.
When i do this to measure the assignment speed of std::string and my string class:
string test1 = " 65 kb text ", test2;
for(int i=0; i<1000000; i++)
{
test2 = test1;
}
mystring test3 = "65 kb text", test4;
for (int i=0; i<1000000; i++)
{
test4 = test3
}
The std::string is a winner by a large margin. I do not do anything in the assignment operator (in my class) but copy with memcpy. I do not even create a new array with the "new" operator, cause i check for size equality, and only request new if needed. How come?
For small strings, there is no problem. I cant see how can std::string assign values faster than memcpy, i bet it uses it too in the background, or something similar, so that's why i asked interning.
Update2:
by modifying the loops with a single character assignment like this: test2[15] = 78, I avoided the effect of copy-on-write of std::string. Now both codes takes exactly the same time (okay, there is an 1-2% difference, but that is negligible). So if I am not entirely mistaken, the mingw std::string must use COW.
Thank you all for your help.
Simply put, no. String interning is not feasible with mutable strings, such as all std::string-objects.
String interning may be done by the compiler only for string literals appearing in the code. If you initialise std:strings with string literals, and some of the literals occur multiple times, the compiler may store only one copy of this string in your binary. There is no string interning at run time. mingw supports compile time string interning as explained before.
Not so much, since std::string is modifiable.
Implementations have been known to attempt the use of copy-on-write, but that causes such problems in multi-threaded code that I think it's out of fashion. It's also very hard to implement correctly - perhaps impossible? If someone takes a pointer to a character in the string, and then modifies another character, I'm not sure that this is permitted to invalidate the first pointer. If it's not allowed, then COW is out of the question too, I think, but I can't remember how it works out.
No, there is no string interning in the STL. It doesn't fit the C++ design philosophy to have such a feature.
Two ideas:
Is myclass a template class? The std::string class is a typedef of the template class basic_string. This means that the complete source of basic_string instead of just the header is accessible to the compiler when your test function is compiled. This additional information enables more optimisations in exchange for higher compilation time.
Most c++ standard library implementations are highly optimised (and sadly almost unreadable).