Case 1
string s1 = "ABCD";
string handles memory allocation to store "ABCD" for you. The string destructor will be called automatically when s1 goes out of scope which will free memory allocated by the string.
s1 = "EFGH";
A string copy assignment operator will overwrite the memory storing "ABCD" with "EFGH".
Case 2
char* val = "ABCD";
val = "EFGH";
Fred Larson answered this question in the comments above, you're just reassigning a pointer to a static string. The stack will allocate memory only for the pointer (not the data), and the pointer will be automatically deallocated when val goes out of scope.
Case 3
string s1 = "ABCD";
string s2 = s1;
s2 will allocate memory and copy s1. A copy on write implementation of the copy assignment operator would only allocate and copy memory if s2 is mutated. However, as of C++11 it seems that COW implementations of std::string are no longer allowed (Legality of COW std::string implementation in C++11).
Case 4
Here is an example of a scenario where you do need to worry about freeing allocated memory.
You might use this if you need a string to outlive the scope in which it was created. (In practice, you should usually avoid this approach. See Case 5 below.)
string* s1 = new string("ABCD");
delete s1;
In this example string is still internally managing memory to store "ABCD", but the string pointer is heap allocated and the string destructor will not be called when s1 goes out of scope. In this case you are responsible for using delete to ensure the memory is cleaned up when s1 is no longer required.
Case 5
shared_ptr<string> s1 = make_shared<string>("EFGH");
shared_ptr is usually the way to go versus new and delete. Shared pointers prevent a lot of memory leaks due to programming mistakes. shared_ptr handles delete for you, and uses reference counting to keep the string alive until the last reference has been destroyed.