Dlaczego konstruktor atomowy std :: zachowuje się inaczej w C ++ 14 i C ++ 17

19

Pracuję w projekcie z C ++ 11 i próbowałem śledzić kod

#include <atomic>

struct A {
    std::atomic_int idx = 1;

};

int main() {
    return 0;
}

Otrzymuję błąd kompilatora

error: use of deleted function 'std::__atomic_base<_IntTp>::__atomic_base(const std::__atomic_base<_IntTp>&) [with _ITp = int]'
 std::atomic_int idx = 1;
                       ^

Ten sam wynik jest w przypadku C ++ 14. Po przejściu na C ++ 17 działa: wandbox

Sprawdziłem preferencje pod kątem różnic:

Ale nie ma udokumentowanej różnicy między C ++ 14 a C ++ 17. Dlaczego działa z C ++ 17, a nie z C ++ 14?

Thomas Sablik
źródło
Z jakiego kompilatora / standardowej biblioteki / platformy korzystasz?
Victor Gubin,
@VictorGubin Próbowałem z Clang i GCC na Linuksie (Wandbox). Próbowałem różnych wersji.
Thomas Sablik,
1
Możesz uprościć MCVE tylko do lokalnego w main(lub dowolnej funkcji, nie ma takiej potrzeby main), zamiast do konstruktora struct. Clang podaje podobny komunikat o błędzie, mówiąc bardziej wyraźnie, że próbuje użyć skasowanego konstruktora kopii zamiast inicjatora lub zwykłego konstruktora: godbolt.org/z/SBGf9w z libc ++
Peter Cordes
@PeterCordes Nie byłem pewien, czy ten błąd jest związany z inicjalizacją klasy.
Thomas Sablik,
3
Otrzymanie tego samego komunikatu o błędzie dla prostszego minimalnego odtwarzalnego przykładu dowodzi, że tak nie jest. Nie byłem pewien, dopóki tego nie spróbowałem.
Peter Cordes,

Odpowiedzi:

29

Ponieważ w C ++ 17 istnieje gwarantowane RVO. W C ++ 14 stwierdzenia jak Foo x = Foo(args)i Foo x (args)technicznie nie są takie same, ale są w C ++ 17.

struct Foo {
    Foo() = default;
    Foo(const Foo&) = delete;
};

int main() {
    // Works in C++17 and C++20, fails in C++14 and before
    Foo foo = Foo(); 
}

Możesz przeczytać więcej na ten temat tutaj: https://en.cppreference.com/w/cpp/language/copy_elision

W szczególności sekcja (since C++17):

T x = T (T (f ())); // tylko jedno wywołanie domyślnego konstruktora T, aby zainicjować x

Aby kod C ++ 14 działał, możesz użyć

std::atomic_int idx { 1 };
Rinat Veliakhmedov
źródło