quick access of hash function (without using string object) - c++

The following code snippet can do hash value on a string object. I would like to get hash value a binary string (a pointer and length). I know I can form a string object with pointer and length, but there is extra overhead to form a string only for that. Wonder if it's possible to use the std hash function with two parameters: pointer and length.
Thanks.
#include <iostream>
#include <functional>
#include <string>
int main()
{
std::string str = "Meet the new boss...";
std::hash<std::string> hash_fn;
std::size_t str_hash = hash_fn(str);
std::cout << str_hash << '\n';
}

I found this article in stack overflow which shows that the underlying hash function is actually a function of the bytes in the string's internal buffer:
What is the default hash function used in C++ std::unordered_map?
But rather than risk undefined behaviour by calling into internal functions within the standard library, why not ask the question, "how much performance will I lose by creating a std::string"? Given that you can always create such a string as a static const (zero overhead) I wonder what you're actually going to save?

Related

Is there a standard library class for substrings?

I have a big read-only string that I scan for syntax and based on that simple syntax I extract a bunch of smaller strings that I use later for further processing. Based on testing, creating and copying most of the big string into the small strings is kind of a performance bottleneck (there are thousands of them per each big string).
I figured that I don't actually need to allocate for-, and copy the data though. What I really need is a sort of string snippet type instead that would only store a pointer to the start of the relevant data and the length but at the same time, it should be a drop-in replacement for std::string and all the standard library interactions it has.
That would be the easiest to implement anyways, I could roll my own class for that and implement the functions I need but if there is already something like it in the standard library then why bother.
So basically, is there a substring sort of class in STL?
Yes, since C++17 you have std::string_view.
Example:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string foo = "Hello world";
std::string_view a(foo.c_str(), 5);
std::string_view b(foo.c_str() + 6, 5);
std::cout << a << '\n' // prints Hello
<< b << '\n'; // prints world
}
This is where using std::string_view instead of std::string is very beneficial in reducing copies of those original strings and being able to use std::string_view::substr.
Instead of copying the strings you are operating on, a string view provides a view to the underlying string - pretty much just the pointer to the start of the string and the size of it.

How can I send a struct of arrays into a function when using the String object?

I'm learning to code c++ and I've come to this problem:
I have this struct:
struct storeData
{
string name;
string username;
string fav_food;
string fav_color;
}data[30];
And I need to check if two usernames are equal so I made this statement:
for(i=0;i<c;i++){
if(data[c].username.compare(data[i].username)==0){
cout<<"Username already taken"<<endl;
}
}
And it works well, the problem that I have is that I'm required to make a function let's call it: isTaken that returns the error message, so I can use it whenever I need to for example delete a username so I don't have to copy/paste the code again.
So I began looking for an answer for that, many forums present a way to send the whole struct like this:
void isTaken(struct storeData *data)
which I understand but because I'm using string is not working, so I guess it's because string is an object? I'm using the library <string> I'm sorry if I'm not being that clear at the moment, I'm looking for a way to use isTaken(data[c].user); but I don't know how to declare the function, I think is also because string is not the same as C string but I'm not really sure I've been looking for a solution and could not find it.
I tried: void isTaken(struct storeData *data) but I got an error saying that I can't convert std::string to basic_string which makes sense if I'm correct about string I tried converting string into c string but could not get anywhere. I'm open to suggestions/corrections because I want to improve my code, also I could not find the answer here, so If someone's got a link to a problem like this please let me know.
Thank you so much for you time, have a good day.
Do you mean an array of structs instead of a struct of arrays?
In the example you are giving I see only an array of structs each of which has multiple string objects in it. You see, a string is a class coming from std and I wouldn't call it an array. If you want to know how to pass an array to a function, you should read about it (I'm sure you can find such a question in SO). If you want to have an array within your struct, then the struct will take care of the memory of the array, but you should definitely read about constructors.
You got an error because you are passing an string argument to a function which requires struct pointer
void isTaken(struct storeData *data);
...
isTaken(data[c].user);
but what you actually need is to have a function which takes an array of your users, its size and username you want to check
bool IsUsernameTaken(struct storeData data[], int dataSize, const string &username){
for(int i = 0; i<dataSize; i++){
if(username == data[i].username)
return true;
}
return false;
}
A C string looks like this
data
A C++ string usually looks like this
size
capacity
ptr
|
v
data
or if using short string optimization and the string is short enough
size
data
data
all are zero terminated.
Making a shallow copy a C string only cost the copy of the pointer to it. Where a copy of a might cost just copying the 3 members and possible an allocation of data, which is not ideal, therefor most C++ functions use a reference to a string making the cost equivalent to the C string.
All code is untested.
bool Find(const std::string& target);
Making a deep copy of a C string would also cost an allocation.
In C++ you have many options to do a search, for your struct it could look like this. In case your member variables are private you must use an access function
auto found = std::find(std::begin(data), std::begin(data)+c, [&target](const storeData& auser) { return auser.GetName() == target });
return (found != std::begin(data)+c);
The first two parameters are the range that is search, not including the 2nd. A lambda is used to check the name, a free function with the right declaration would also do.
std::string& GetName() { return name; }
The higher C++ protection schemes would advice adding 2 consts to that in case you don't need to change name.
const std::string& GetName() const { return name; }
Meaning the returned string cant be changed and the 2nd says it wont change anything in your class. This const version would be required as I used a const storeData& auser in the lambda to satisfy the constness of the struct.

What's the necessity of string in c++ while we already have char[]?

Many topics have discussed the difference between string and char[]. However, they are not clear to me to understand why we need to bring string in c++? Any insight is welcome, thanks!
char[] is C style. It is not object oriented, it forces you as the programmer to deal with implementation details (such as '\0' terminator) and rewrite standard code for handling strings every time over and over.
char[] is just an array of bytes, which can be used to store a string, but it is not a string in any meaningful way.
std::string is a class that properly represents a string and handles all string operations.
It lets you create objects and keep your code fully OOP (if that is what you want).
More importantly, it takes care of memory management for you.
Consider this simple piece of code:
// extract to string
#include <iostream>
#include <string>
main ()
{
std::string name;
std::cout << "Please, enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!\n";
return 0;
}
How would you write the same thing using char[]?
Assume you can not know in advance how long the name would be!
Same goes for string concatenation and other operations.
With real string represented as std::string you combine two strings with a simple += operator. One line.
If you are using char[] however, you need to do the following:
Calculate the size of the combined string + terminator character.
Allocate memory for the new combined string.
Use strncpy to copy first string to new array.
Use strncat to append second string to first string in new array.
Plus, you need to remember not to use the unsafe strcpy and strcat and to free the memory once you are done with the new string.
std::string saves you all that hassle and the many bugs you can introduce while writing it.
As noted by MSalters in a comment, strings can grow. This is, in my opinion, the strongest reason to have them in C++.
For example, the following code has a bug which may cause it to crash, or worse, to appear to work correctly:
char message[] = "Hello";
strcat(message, "World");
The same idea with std::string behaves correctly:
std::string message{"Hello"};
message += "World";
Additional benefits of std::string:
You can send it to functions by value, while char[] can only be sent by reference; this point looks rather insignificant, but it enables powerful code like std::vector<std::string> (a list of strings which you can add to)
std::string stores its length, so any operation which needs the length is more efficient
std::string works similarly to all other C++ containers (vector, etc) so if you are already familiar with containers, std::string is easy to use
std::string has overloaded comparison operators, so it's easy to use with std::map, std::sort, etc.
String class is no more than an amelioration of the char[] variable.
With strings you can achieve the same goals than the use of a char[] variable, but you won't have to matter about little tricks of char[] like pointers, segmentation faults...
This is a more convenient way to build strings, but you don't really see the "undergrounds" of the language, like how to implement concatenation or length functions...
Here is the documentation of the std::string class in C++ : C++ string documentation

C++ Combine strings for 'system' function error

I'm having this c++ error which I can't really understand(I'm new to c++). I think the code should work, but it does not. So I came to ask for help.
Code:
#include <iostream>
#include <cstdlib>
using namespace std;
class Cpy{
public:
string exc;
void cpy(string pyfile){
exc = "python" + pyfile;
system(exc);
}
};
int main(){
Cpy ex;
ex.cpy("example.py");
}
std::system() expects its string in the form of a pointer to a null-terminated array of char. You cannot hand it an std::string directly. You can use the c_str() method of std::string to get a pointer to a null-terminated version of the std::string's contents:
system(exc.c_str());
Also, you most likely forgot to put a space between "python" and your argument.
Apart from that, exc should most likely be a local variable inside your cpy() method rather than a member of the class Cpy.
Instead of passing an std::string object by value I'd consider to rather pass the pyfile argument to cpy() in form of an std::string_view (if your compiler supports C++17) or a plain const char*. Furthermore, if you want to build more complex strings, you might want to consider using an std::ostringstream instead of just concatenating string objects:
void cpy(string_view pyfile)
{
ostringstream cmd;
cmd << "python " << pyfile;
system(exc.str().c_str());
}
For just two strings, it won't matter. But if you want to concatenate many more strings or, e.g., also incorporate numbers and other stuff that needs formatting into your string, using a stringstream would generally seem to be a better idea.

Making a method template - C++

Below code is used to get a std::string representation from ASCII code.
string Helpers::GetStringFromASCII(const int asciiCode) const
{
return string(1,char(asciiCode));
}
It works well. But in my application, I know the ASCII codes at compile time. So I will be calling it like
string str = GetStringFromASCII(175) // I know 175 at compile time
Question
Is there any way to make the GetStringFromASCII method a template so that the processing happens at compile time and I can avoid calling the function each time at runtime.
Any thoughts?
This kind of template meta programming works well when you're dealing with primitive data types like ints and floats. If you necessarily need a string object, you can't avoid calling the std::string constructor and there's no way that call can happen at compile time. Also, I don't think you can drag the cast to char to compile time either, which, in all, means that templates cannot help you here.
Instead of feeding an int constant to a string conversion function, use a string constant directly:
string str("\xAF"); // 0xAF = 175
By the way, except for heavy performance needs in a loop, trading code readability for some CPU cycles is rarely money effective overall.
Why are you even bothering with a helper function?
string s( 1, char(175) );
That's all you need and it's the quickest you're going to get.
How about something like this:
#include <iostream>
#include <string>
using namespace std;
template <int asciiCode>
inline string const &getStringFromASCII()
{
static string s(1,char(asciiCode));
return s;
}
int main(int, char const**) {
cout << getStringFromASCII<65>() << endl;
}
EDIT: returns a ref now