Pourquoi le constructeur std :: atomic se comporte-t-il différemment en C ++ 14 et C ++ 17

19

Je travaille dans un projet avec C ++ 11 et j'ai essayé de suivre le code

#include <atomic>

struct A {
    std::atomic_int idx = 1;

};

int main() {
    return 0;
}

J'obtiens l'erreur du compilateur

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

Le même résultat est avec C ++ 14. Quand je passe en C ++ 17 ça marche: wandbox

J'ai vérifié cppreference pour les différences:

Mais il n'y a aucune différence documentée entre C ++ 14 et C ++ 17. Pourquoi ça marche avec C ++ 17 et pas avec C ++ 14?

Thomas Sablik
la source
Quel compilateur / bibliothèque standard / plateforme utilisez-vous?
Victor Gubin
@VictorGubin J'ai essayé avec Clang et GCC sur Linux (Wandbox). J'ai essayé différentes versions.
Thomas Sablik
1
Vous pouvez simplifier le MCVE à juste un local dans main(ou n'importe quelle fonction, pas besoin qu'il soit main), au lieu d'un constructeur struct. Clang donne un message d'erreur similaire, étant plus explicite qu'il essaie d'utiliser un constructeur de copie supprimé au lieu d'un initialiseur ou d'un constructeur simple: godbolt.org/z/SBGf9w avec libc ++
Peter Cordes
@PeterCordes Je n'étais pas sûr que cette erreur soit liée à l'initialisation de la classe.
Thomas Sablik
3
Obtenir le même message d'erreur pour un exemple reproductible minimal plus simple prouve que ce n'est pas le cas. Je n'étais pas sûr non plus avant de l'avoir essayé.
Peter Cordes

Réponses:

29

Parce qu'en C ++ 17 il y a un RVO garanti. En C ++ 14, les instructions comme Foo x = Foo(args)et Foo x (args)techniquement ne sont pas identiques, mais elles sont en 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(); 
}

Vous pouvez en savoir plus à ce sujet ici: https://en.cppreference.com/w/cpp/language/copy_elision

En particulier la section (since C++17):

T x = T (T (f ())); // un seul appel au constructeur par défaut de T, pour initialiser x

Pour faire fonctionner le code C ++ 14, vous pouvez utiliser

std::atomic_int idx { 1 };
Rinat Veliakhmedov
la source