I have CString cs on C++ side and IntPtr ip on C# side which contains value of cs through marshaling mechanism.
Then, I simply get needed String as Marshal.PtrToStringAnsi(ip) and everything works fine, but I am wondering should I and if should, how can I delete unmanaged memory occupied by ip, i.e. cs?
You can't, you have no idea what allocator was used by the unmanaged code to create the CString instance. Moreover, you'd have to call the CString destructor, you can't get its address.
You are dead in the water if this CString object is returned as the function return value of a C++ function that you call from C#. It isn't clear from your question. You'll have an uncontrollable memory leak. A wrapper written in C++/CLI will be required to fix that problem. Strings returned as function return values must be allocated by CoTaskMemAlloc() to get properly cleaned up by the P/Invoke marshaller. No C++ code ever does that.