C ++ strings without <string> and STL
I haven’t used C ++ much in the past, and lately I've been working a lot with C #, and I'm really struggling to get back to the basics of C ++ again. This is especially difficult, since the work indicates that you cannot use any of the most convenient C ++ constructs, so all strings must be * characters, and no provision is made for STL lists.
What I'm trying to do now is to create a list of strings that won’t take me time to use STL or C #. Basically I want to have a function like:
char **registeredNames = new char*[numberOfNames]; Then,
RegisterName(const * char const name, const int length) { //loop to see if name already registered snipped if(notFound) { registeredNames[lastIndex++] = name; } } or if it was C # ...
if(!registeredNames.Contains(name)) { registeredNames.Add(name); } and I understand that this does not work. I know that the constant nature of the variables passed (constant pointer and constant string) makes this quite difficult, but my main problem is that I always avoided this situation in the past using STL lists, etc., so I never had to work around this is!
You will probably need to use strcmp to find out if the string is saved:
for (int index=0; index<=lastIndex; index++) { if (strcmp(registeredNames[index], name) == 0) { return; // Already registered } } Then, if you really need to keep a copy of the string, you will need to allocate a buffer and copy the characters.
char* nameCopy = malloc(length+1); strcpy(nameCopy, name); registeredNames[lastIndex++] = nameCopy; You did not indicate whether your NULL entry is complete - if not, you need additional help, and strcmp / strcpy is not suitable.
There are legitimate reasons why STL can be avoided. When working in fixed environments where memory or speed is paramount, it is sometimes difficult to say what happens under the hood with STL. Yes, you can write your own memory allocators, and yes, speed is usually not a problem, but there are differences between STL implementations on different platforms, and these differences can be subtle and potentially erroneous. Memory is perhaps the biggest problem when I think about using it.
Memory is precious, and the way we use it requires tight control. If you have not taken this path, this concept may not make sense, but it is true. We allow the use of STL in tools (outside the game code), but this is prohibited inside the game itself. Another issue is code size. I'm a little unsure how much STL can contribute to the size of the executable, but we have seen a noticeable increase in code size when using STL. Even if your executable is “only” 2M larger, it is 2M less RAM for something else for your game.
STL is certainly good. But this can be abused by programmers who do not know what they are doing. This is not intentional, but can bring unpleasant surprises when you do not want to see them (again, memory overflow and performance problems)
I am sure that you are close with your decision.
for ( i = 0; i < lastIndex; i++ ) { if ( !strcmp(®isteredNames[i], name ) { break; // name was found } } if ( i == lastIndex ) { // name was not found in the registeredNames list registeredNames[lastIndex++] = strdup(name); } You might not want to use strdup. This is just an example of how to store a name based on your example. You might want to make sure that you either don’t want to allocate space for the new name yourself, or use some other memory design that may already be available in your application.
And please don't write a string class. I looked at string classes as perhaps the worst example of how not to reverse-engineer the underlying C construct in C ++. Yes, the string class can hide a lot of nifty details from you, but the memory usage patterns are terrible, and they fit poorly into the console environment (e.g. ps3 or 360, etc.). About 8 years ago we did the same. 200000+ memory allocation before we get to the main menu. The memory was terribly fragmented, and we could not get the rest of the game to fit into a fixed environment. We are done with this.
Class design is great for some things, but it's not one of them. This is an opinion, but it is based on the experience of the real world.
If you really can't use stl (and I'm sorry that this is true when I was in the gaming industry), can you create your own class of strings? The simplest of the string classes will allocate memory for construction and assignment and handle deletion in the destructor. Later you could add additional features as needed. Fully portable and very easy to write and unit test.
Edit: I think I misunderstood your question. There is no problem with the constant in this code that I know of.
I am doing this from my head, but this should be correct:
static int lastIndex = 0; static char **registeredNames = new char*[numberOfNames]; void RegisterName(const * char const name) { bool found = false; //loop to see if name already registered snipped for (int i = 0; i < lastIndex; i++) { if (strcmp(name, registeredNames[i] == 0)) { found = true; break; } } if (!found) { registeredNames[lastIndex++] = name; } } Working with char * requires working with C functions. In your case, you need to copy the lines. To help you, you have the strndup function. Then you have to write something like:
void RegisterName(const char* name) { // loop to see if name already registered snipped if(notFound) { registerNames[lastIndex++] = stdndup(name, MAX_STRING_LENGTH); } } This code suppose your array is big enough.
Of course, it would be best to correctly implement your own string, array, and list ... or convince your boss that STL is no longer evil!
If you're not worried about agreements and just want to get the job done, use realloc. I do such things for lists all the time, it happens something like this:
T** list = 0; unsigned int length = 0; T* AddItem(T Item) { list = realloc(list, sizeof(T)*(length+1)); if(!list) return 0; list[length] = new T(Item); ++length; return list[length]; } void CleanupList() { for(unsigned int i = 0; i < length; ++i) { delete item[i]; } free(list) } You can do more, for example. only realloc every time the size of the list is doubled, functions to remove items from the list by index or by checking equality, creating a template class to process lists, etc. (I have one that I wrote many years ago and always use myself ... but, unfortunately, I'm at work and can't just copy it here). To be completely honest, this probably will not exceed the STL equivalent, although it can be compared to its performance if you are doing a ton of work or doing STLs especially poorly.
Annoyingly C ++ does not update / modify the operator to replace realloc, which would be very useful.
Oh, and apologies if my code is wrong, I just pulled it out of memory.
All the proposed approaches are valid, my point is that the way C # is attractive, replicates it, creates its own classes / interfaces to represent the same abstraction, i.e. a simple linked list class with Contains and Add methods using a code sample provided by other answers should be relatively simple.
One of the great features of C ++ is that, as a rule, you can make it look and act the way you want if the other language has a great implementation of what you can usually reproduce.
Conjugate correctness is still correct, regardless of whether you use STL or not. I believe that you are looking to register const char ** a const char ** so that the registeredNames[i] assignment (which is const char * ) is executed.
Also, is this really what you want to do? It seems like a copy of the string is probably more appropriate.
In addition, you should not think about keeping this in the list, given the operation you perform on it, but it will be better.
I have used this String class for many years.
http://www.robertnz.net/string.htm
It provides almost all STL functions, but is implemented as a true class, not a template, and does not use STL.