Why would a new[] expression ever invoke a destructor?

In action:

#include <iostream>

int counter;

class Destruct
{
public:
    Destruct()
    {
        if (counter++ > 5)
            throw counter;
    }

    ~Destruct()
    {
        std::cout << "Dtor called\n";
    }
};

int main()
{
    try
    {
        new Destruct[10];
    }
    catch (...){}
}

You'll see output something like:

Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called

You have not considered the word "potentially" in the quote you have mentioned from the standard.
It means that there is a possibility that invocation of the destructor can happen. And it will happen if construction of any object in the array throws an exception.

Combined with the following quote from [class.dtor]/12.4 which mentions [expr.new], this becomes clear.

In each case, the context of the invocation is the context of the construction of the object. A destructor is also invoked implicitly through use of a delete-expression for a constructed object allocated by a new-expression; the context of the invocation is the delete-expression. [ Note: An array of class type contains several subobjects for each of which the destructor is invoked.  — end note ] A destructor can also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in [expr.new], [class.base.init], and [except.throw]. A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.


If construction of any object in the buffer throws an exception, the previously constructed objects must be destructed. That requires an available destructor.