views:

423

answers:

9

How does string expressions in C++ work?

Consider:

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){

    const char *tmp="hey";
    delete [] tmp;

    return 0;
}

Where and how is the "hey" expression stored and why is there segmentation fault when I attempt to delete it?

+4  A: 

You can't delete static resources: those are Read-Only.

jldupont
+12  A: 

Where it's stored is left to the compiler to decide in this (somewhat special) case. However, it doesn't really matter to you - if you don't allocate memory with new, it's not very nice to attempt to deallocate it with delete. You cannot delete memory allocated in the way you have allocated it.

If you want to control the deallocation of that resource, you should use a std::string, or allocate a buffer using malloc().

Nick Bastin
oh... so it's not very recommended to use pointers on const char data i suppose
stupid_idiot
@stupid_idiot: You are free to use a pointer to reference const char data, just don't try to delete the memory referenced by the pointer.
Nick Bastin
@Nick, I would add too that if you allocate with `malloc`, you should also be sure to free with `free`.
Nick Meyer
@Nick Meyer: Good point. That seemed beyond the scope of the current discussion somehow.. :-)
Nick Bastin
+1  A: 

You can't delete constant data. You would only call delete[] tmp if you had previously called new char[stringSize].

ruibm
+11  A: 

When you assign a const char * pointer to a constant string like "hey" in the example, the hey\0 sequence is stored as a static variable inside the binary itself. It cannot be deleted, and should not be manipulated. Depending on the architecture/operating system, it may segfault when manipulated.

If you were to do const char[] tmp = "hey" then the data would be stored on the stack, and may be manipulated (but not deleted, as it will be freed once the stack clears: when the function returns).

Do not delete[] anything that isn't new[]'d.

Sufian
+1  A: 

You did not call new on the string. That is a potential memory leak anyway, for every new there is a delete, likewise same for malloc and free. You deleted a memory reference to a pointer that simple is a static array of chars, in the sense of the word.

Hope this helps, Best regards, Tom.

tommieb75
+4  A: 

What happens is this.

"hey" means put string 'hey' into binary image somewhere and give me an address of it, which is the value of the expression ("hey"). It has type char*. At this address, you have 4 bytes. 'h', 'e', 'y', and 0 (0 is called conventional null-terminator. (nothing to do with the movie terminator) This is how string literals work in C.

You can pass this literal as such: "an address of a string".

You cannot delete it.

when you construct std::string("hey"), it takes this pointed string, and copies it elsewhere - into a newly allocated memory.

Pavel Radzivilovsky
+6  A: 

The "hey" is a string literal and is stored in the executable's data segment, which is mapped into memory of the process at load time. The particular part where literals live is mapped read-only. Here's a snippet of the assembly produced from your code with g++ -S:


...
    .section    .rodata
.LC0:
    .string "hey"
    .text
    .align 2
...

So the data is indeed read-only, and attempt to manipulate it with delete leads to segfault.

Nikolai N Fetissov
A: 

The string "hey" has its space pre-allocated as part of the program, so it just appears when the program starts and disappears when the program ends.

If you want to see a program that allocates memory, uses it, then deletes it, then look at this:

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){

    const char *hey="hey";
    char* tmp=new char[4]; // NB allocate 4 chars for "hey" plus a null terminator
    strcpy(tmp,hey);  // copies the string and null terminator
    cout << tmp << endl;
    delete [] tmp;
    // must not use tmp now as it points to deallocated memory
    // must not delete hey

    return 0;
}

Notice how I happened to delete the new'd memory using tmp. I could have done this:

    cout << tmp << endl;
    hey = tmp;
    delete [] hey;

It doesn't matter whether, in the end, we point to the new'd memory with hey or tmp, just as long as we delete it properly to avoid memory leaks.

quamrana
+1  A: 

const char *tmp="hey";

"hey" is stored in a read-only area of the Data Segment. When the application starts up "hey" will be mapped to the READ-ONLY memory page.

const char *tmp="hey";
delete [] tmp;

delete will access and change some allocation metadata., but "hey" in the READ-ONLY memory page.

Changing value in READ-ONLY is not allowed, so segmentation fault happened.

whunmr