Kolejność wykonywania operatora new i argument konstruktora

9

Czy specyfikacja C ++ określa kolejność operator newi konstruktor Aw new C(A()).
G ++ niech kolejność będzie A()-> new-> C(), ale clang ++ niech będzie new-> A()-> C().
Czy różnica jest spowodowana nieokreślonym zachowaniem?

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());
}
Eddie Kuo
źródło
3
Budujesz jako C ++ 17, C ++ 14 lub wcześniejszy?
StoryTeller - Unslander Monica,
4
Dwie notatki: Oznaczono to tagiem „C”, co wyraźnie pokazuje, że nie przeczytałeś opisu tego tagu. Nie rób Teraz pytasz o „niezdefiniowane zachowanie” (UB). Jest to termin używany przez standard C ++ do oznaczania rzeczy, w których wszystko może się zdarzyć i których należy unikać. Istnieje również „nieokreślone zachowanie”, które prawdopodobnie jest bliższe temu, czego szukasz, ponieważ kod jest poprawny technicznie i nie powoduje UB.
Ulrich Eckhardt
1
@Ulrich Eckhardt Dziękujemy za sugestię. Wymieszałem te dwa.
eddie kuo

Odpowiedzi:

11

Clang ma rację. Od wersji C ++ 17 kolejność wykonania jest gwarantowana. [expr.new] / 19

Wywołanie funkcji alokacji jest sekwencjonowane przed ocenami wyrażeń w nowym inicjalizatorze .

operator new(funkcja alokacji) powinna być najpierw wywołana, a następnie ocena wyrażenia w nowym inicjalizatorze (tj A().).

Przed wersją C ++ 17 zamówienie nie jest gwarantowane. [expr.new] / 18 (C ++ 14)

Wywołanie funkcji alokacji jest sekwencyjnie nieokreślone w odniesieniu do ocen wyrażeń w nowym inicjalizatorze .


Wygląda na to, że gcc nie jest zgodne z C ++ 17 (i nowszymi); kompilacja z gcc10 w trybie C ++ 2a daje ten sam wynik.

songyuanyao
źródło