Question

So the title is my question. In memory, arguments can be located on the stack or heap depending on how they are initialized, but how is hard-coded information dealt with?

As an example, I will use the constructor for ifstream

What is the difference between this:

void function(){

    ifstream infile("home/some/file/path");

}

vs

void function(char* filePath){

    ifstream infile(filePath); //filePath points to a character array which contains home/some/file/path

}

Could any memory implications arise from the use of one over the other? (Multithreading could lead to heap corruption if the char* isn't free'd correctly? etc).

I am just trying to understand the difference and possible implications so I can apply the answer to a larger problem. All insight is welcome and feel free to correct me if I've made any incorrect statements/assumptions!

Was it helpful?

Solution

Literals (which is what your first example shows) are placed into the static initialization portion of the executable (which is why, if you are on a *Nix system), you can use the command strings and obtain a list of all the literals in the application.

Your 2nd example should actually be modified to

void function(const char* filePath) { ... }

Unless you are going to modify the pointer in the function. The memory for that function can come from anywhere (a string literal being passed into the function, a constant string declared somewhere else in the application, a string stored in memory and inputted from the command line or console, etc.)

The primary issue you will run into with Multithreading here is if 2+ threads are attempting to load the same file at the same time. It may not be a problem if they are all reading it, but if you have a thread that wants to write to it and obtains an exclusive lock on the file, the other threads will deadlock. This isn't directly related to your strings question, though.

OTHER TIPS

Others have pretty well covered that a literal string is stored in some read-only memory in the executable, and the pointer to char is just pointing directly at that memory.

Whether your second option is "good", "bad" or "none of the above" depends highly on what the origin of filePath is.

Clearly, if some code is doing char *filename = new char [x]; strcpy(filename, "..."); then there needs to be a corresponding delete [] filename; - and the x needs to be long enough for the string "..." to fit.

It is safer to use std::string in this case, as any allocation is dealt with by the class, and the de-allocation dealt with in the destructor.

If we throw threads into the equation, we will also have to worry about where the strings are defined. In a class that has only one instance, as a global variable or on the stack. Only "stack" is safe, and with restrictions: if you pass a pointer to char * from main [or some other function before the thread is created] into the thread, you could have all sorts of "fun" with memory being allocated multiple times into a single string, data being overwritten by other threads, and what have you. Of course, if the threads aren't CHANGING the data, there is also no problem with global variable or stack from outside the thread.

This is what I meant by "it depends on how the string is created". The details are definitely what matters here.

The "hard-coded" or literal values are usually part of the instructions of the program. For example if I do something like

int i = 0;

the value of 0 is loaded using assembly commands at the architectural level. So what I am getting at is that they are handled by the compiler and program, and probably either will use no memory at all, or be on the stack.

For the values such as char*, first off I would recommend using strings, as they handle the memory allocation accordingly, but large strings are often stored on the heap, while small strings (less than 7 chars or so) can be optimized to be handled on the stack (unless "new" is involved).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top