I see three main problems with your code:
Each of them is undesirable for its own reasons. I will try to explain each of them in turn.
(1) violates what I like to call subexpressive correctness, and (2) violates the correctness of the wording. The idea here is that no statement, or even any subexpression, in itself should be a mistake. I accept the term “mistake” freely to mean “may be a mistake”.
The idea of writing good code is that if it goes wrong, it is not your fault. Your basic thinking should be like a paranoid coward. Not writing code at all is one way to achieve this, but since it rarely meets the requirements, it’s best to make sure that whatever you do is not your fault. The only way you can systematically prove that this is not your mistake is that not a single part of your code is the main cause of the error. Now consider the code again:
new std::string[25] - an error because it creates a dynamically allocated object that has leaked. This code can conditionally become not an error if someone else, somewhere else and in each case, remembers to clear it.
This requires, first of all, that the meaning of this expression be stored somewhere. This happens in your case, but in more complex terms it can be difficult to prove that it will ever happen in all cases (unspecified order of evaluation, I look at you).
foo = new std::string[125]; is a mistake, because again foo a resource leak, unless the stars are aligned, and someone remembers, in each case and at the right time, to clear.
The correct way to write this code so far would be as follows:
std::unique_ptr<std::string[]> foo(std::make_unique<std::string[]>(25));
Note that each subexpression in this expression is not the main cause of a program error. This is not your mistake.
Finally, with regard to (3), dynamic arrays are errors in C ++ and, in principle, will never be used. There are several standard defects that apply only to dynamic arrays (and are not considered worthy of fixation). The simple argument is that you cannot use arrays without knowing their size. You could say that you can use the value of the watch or tombstone to dynamically mark the end of the array, but this makes the correctness of your program cost-dependent and not type-dependent and therefore not statically checked (the definition itself is "unsafe" ") You cannot say that this is not your fault.
Thus, you still have to maintain separate storage for the size of the array. And guess what, your implementation should duplicate this knowledge anyway, so that it can name destructors when you say delete[] to unravel the empty one. Instead, the correct way is not to use dynamic arrays, but instead to allocate memory allocation (and make it customizable using allocators, why are we on it), from creating an elementary object. Wrapping all of this (allocator, storage, number of elements) in one convenient class is a C ++ method.
So the final version of your code is this:
std::vector<std::string> foo(25);