Порядок выполнения оператора new и аргумента конструктора

9

Спецификация C ++ определяет порядок operator newи конструктор Aв new C(A()).
G ++ пусть порядок будет A()-> new-> C(), но clang ++ пусть это будет new-> A()-> C().
Разница вызвана неопределенным поведением?

g ++: 7.4.0 clang ++: 10.0.0

#include <iostream>
#include <cstdlib>

struct A {
    A() {
        std::cout << "call A()\n";
    }
};

struct C {
    C(A) {
        std::cout << "call S()\n";
    }

    void *operator new(size_t s) {
        std::cout << "call new()\n";
        return malloc(s);
    }
};

int main() {
    void *p = new C(A());
}
Эдди Куо
источник
3
Вы строите как C ++ 17, C ++ 14 или ранее?
StoryTeller - Unslander Моника
4
Два примечания: Вы пометили это как «C», что ясно показывает, что вы не читали описание этого тега. Не. Теперь вы спрашиваете о «неопределенном поведении» (UB). Это термин, используемый стандартом C ++ для обозначения вещей, где что-то может произойти и чего следует избегать. Существует также «неопределенное поведение», которое, вероятно, ближе к тому, что вы ищете, потому что код технически исправен и не вызывает UB.
Ульрих Экхардт
1
@ Ульрих Экхардт Спасибо за ваше предложение. Я перепутал два.
Эдди Куо

Ответы:

11

Clang это правильно. Начиная с C ++ 17 порядок выполнения гарантирован. [expr.new] / 19

Вызов функции распределения выполняется до оценки выражений в новом инициализаторе .

operator new(функция распределения) должна вызываться сначала, а затем вычислять выражение в новом инициализаторе (т.е. A()).

До C ++ 17 порядок не гарантирован. [expr.new] / 18 (C ++ 14)

Вызов функции размещения неопределенно упорядочен относительно вычислений выражений в новом инициализаторе .


Кажется, что gcc не соответствует C ++ 17 (и позже); компиляция с gcc10 в режиме C ++ 2a дает тот же результат.

songyuanyao
источник