EDIT: The question about why the code in this question works has been answered by the linked question in the duplicate marking. The question about string literal lifetime is answered in the answer to this question.
I am trying to understand how and when the string pointed to by const char *
gets deallocated.
Consider:
const char **p = nullptr;
{
const char *t = "test";
p = &t;
}
cout << *p;
After leaving the inner scope I would expect p
to be a dangling pointer to const char *
. However in my tests it is not. That would imply that the value of t
actually continues to be valid and accessible even after t
gets out of scope.
It could be due to prolonging the lifetime of the temporary by binding it to const reference. But I do no such thing and even by saving the reference to t
in a member variable and printing the value from different function later still gives me its correct value.
class CStringTest
{
public:
void test1()
{
const char *t = "test";
m_P = &t;
test2();
}
void test2()
{
cout << *m_P;
}
private:
const char **m_P = nullptr;
};
So what is the lifetime of the t
's value here? I would say I am invoking undefined behaviour by dereferencing a pointer to a value of a variable that went out of scope. But it works every time so I think that is not the case.
When trying some other type like QString
:
QString *p = nullptr;
{
QString str = "test";
p = &str;
}
cout << *p;
the code always prints the value correctly too even though it should not. str
went out of scope with its value and I have not prolonged its lifetime by binding it to const reference either.
Interestingly the class example with QString
behaves as I would expect and test2()
prints gibberish because the value indeed went out of scope and m_P
became dangling pointer.
So what is the actual lifetime of const char *
's value?
const char* const says that the pointer can point to a constant char and value of int pointed by this pointer cannot be changed. And we cannot change the value of pointer as well it is now constant and it cannot point to another constant char.
const char* is a mutable pointer to an immutable character/string. You cannot change the contents of the location(s) this pointer points to. Also, compilers are required to give error messages when you try to do so. For the same reason, conversion from const char * to char* is deprecated.
The const char *Str tells the compiler that the DATA the pointer points too is const . This means, Str can be changed within Func, but *Str cannot. As a copy of the pointer is passed to Func, any changes made to Str are not seen by main....
The difference is that const char * is a pointer to a const char , while char * const is a constant pointer to a char . The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).
The variables p
and t
are stack variables that you declared, so they have a lifetime that ends at the end of their enclosing block.
But the value of t
is the address of the string literal "test"
, and that is not a variable you declared, it's not on the stack. It's a string literal, which is a constant defined in the program (similar to the integer literal 99
or the floating point literal 0.99
). Literals don't go out of scope as you expect, because they are not created or destroyed, they just are.
The standard says:
Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above.
So the object that the compiler creates to represent the literal "test"
has static storage duration, which is the same duration as globals and static
variables, meaning it doesn't go out of scope like a stack variable.
The value of p
is the address of t
, which does become an invalid pointer when t
goes out of scope, but that doesn't mean that the value stored at that address suddenly becomes inaccessible or gets wiped. The expression *p
is undefined behaviour, but it appears to work because nothing has reused that memory location yet so *p
still contains the address of the string literal. For more details on that see the top answer to Can a local variable's memory be accessed outside its scope?
Compilers put literal strings into a statically allocated space which is loaded into a protected segment of the virtual memory, such that those strings can be shared over the entire lifetime of the process (the value is a constant, so no need to take the overhead of constantly springing them into existence). Looking for something like that to be deallocated is a waste of time, since it never actually happens.
The variables are stack-allocated. The string constant should be thought of as just that: a string constant...like the number 3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With