15

I am aware that the following code will create an array of characters and remain in memory until the program ends:

char* str = "this is a string";

As for this statement, creates a local array of characters and will be freed when str goes out of scope:

char str[] = "this is a string";

What I'm curious is, what happens when I write it like this:

std::string str = "this is a string";

str should make a copy of the string in it's own memory (local), but what about the string literal itself? Will it have the lifetime of the program or will it be freed when str goes out of scope?

2
  • 6
    a string literal has static storage duration, so it always lives for the entire lifetime of the program. Commented Sep 5, 2015 at 13:43
  • std::basic_string does not own the literal, so its lifetime is not determined by str's. Commented Sep 5, 2015 at 13:44

4 Answers 4

17

When you write this

std::string str = "this is a string";

C++ should find a constructor of std::string that takes const char*, calls it to make a temporary object, invokes the copy constructor to copy that temporary into str, and then destroys the temporary object.

However, there is an optimization that allows C++ compiler to skip construction and destruction of the temporary object, so the result is the same as

std::string str("this is a string");

but what about the string literal itself? Will it have the lifetime of the program or will it be freed when str goes out of scope?

String literal itself when used in this way is not accessible to your program. Typically, C++ places it in the same segment as other string literals, uses it to pass to the constructor of std::string, and forgets about it. The optimizer is allowed to eliminate duplicates among all string literals, including ones used only in the initialization of other objects.

Sign up to request clarification or add additional context in comments.

2 Comments

IIRC, No operator= may be invoked here, as that would require a constructed objects on both sides. Instead, initialization with = calls the copy constructor.
@Oberon You are right, it's a copy constructor. I fixed the answer, thank you very much!
7

most of the OS will partition your program memory into few parts

  • The Stack
  • The Heap
  • The Data segment
  • The BSS segment
  • The Code segment

you already know about the stack and the heap, but what about the others?

the code segment keeps all the operations in binary form.

now it gets interesting: let's see the following code:

int x;
class Y{  static int y;  };
int main(){
  printf("hello world");
  return 0;
}

where does the program allocates x and y? they are not local or dynamically allocated, so where?

The Data segment keeps all the static and global variables, when the program is being loaded, this segments keeps enough bytes to hold all the static and global variables. if the variable is an object, when the program goes up it allocates enough bytes for all the variables, including the objects. before main the program calls each global object constructor, and after the main finishes it call each object destructor in reverse order it called the constructor.

The BSS segment is a sub-set of the Data segment which keeps global and static pointers which are null-intitalized.

So assuming the string literal wasn't optimized away, the program stores it in the data segment. It will live on as long as the program lives. moreover, if it's a string literal, most likely you can even see it inside the exe! open the exe as a text file. some point along the way, you will see the string clearly.

Now what about std::string str = "hello world"; ?

This is a funky situation. str itself lives on the stack. The actual inner buffer lives on the heap, but the string literal which used to assign the string lives in the data segment and the code which makes str value turn into hello world lives in the code segment. needless to say, if we were to program in assembly, we would need to build this ecosystem with our own bare-hands.

Comments

2

I will offer a counter question: why do you care?

The C++ Standard specifies the behavior of the language, and the first core principle when it comes to implementations is basically known as the as-if rule:

§ 1.9 Program execution

1/ The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.


In your case:

std::string str = "this is a string";

There are various valid scenarios:

  • you do not use str afterward? then this whole code portion may be completely elided
  • you immediately assign 'T' to str[0] afterward? then the two might be coalesced into std::string str = "This is a string";
  • ...

and there is no guarantee as to what your compiler will do. It may depend on the compiler you use, the standard library implementation you use, the architecture/OS you are compiling for and even the arguments passed to the compiler...

Thus, if you want to know in your case, you will have to inspect the machine code generated. Asking coliru, for the following code:

#include <string>

int main(int argc, char** argv) {
    std::string str = "this is a string";
}

Clang produces the following in the IR:

@.str = private unnamed_addr constant [17 x i8] c"this is a string\00", align 1

which in turn gives the following assembly:

.L.str:
    .asciz    "this is a string"
    .size .L.str, 17

So you have it, for these specific conditions, "this is a string" will be as-is in the binary and will be loaded in read-only memory. It will stay in the address space of the process until the end, the OS may page it out or not depending on RAM pressure.

Comments

0

A few of your initial statements are not quite correct:

For the char * and char [] example, in both cases the variable itself, str remains in scope and accessible until the program ends if it's declared in the global namespace.

If it's declared in a function or a method's scope, it's accessible while the scope remains active. Both of them.

As far as what actually happens to the memory that's used to store the actual literal strings, that's unspecified. A particular C++ implementation is free to manage runtime memory in whatever manner is more convenient for it, as long as the results are compliant with the C++ standard. As far as C++ goes, you are not accessing the memory used by the str object, you're only referencing the str object itself.

Of course, you are free to take a native char * pointer, pointing to one of the character in the str. But whether or not the pointer is valid is tied directly to the scope of the underlying object. When the corresponding str object goes out of scope, the pointer is no longer valid, and accessing the contents of the pointer becomes undefined behavior.

Note that in the case where str is in the global namespace, the scope of str is the lifetime of the program, so the point is moot. But when str is in a local scope, and it goes out of scope, using the pointer becomes undefined behavior. What happens to the underlying memory is irrelevant. The C++ standard doesn't really define much what should or should not happen to memory in the underlying implementation, but what is or is not undefined behavior.

Based on that, you can pretty much figure out the answer for the std::string case yourself. It's the same thing. You are accessing the std::string object, and not the underlying memory, and the same principle applies.

But note that in addition to the scoping issue, some, but not all, methods of the std::string object are also specified as invalidating all existing direct pointers, and iterators, to its contents, so this also affects whether or not a direct char * to one of the characters in the std::string remains valid.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.