Ich habe meine C ++ - Toolchain von Visual Studio 2013 auf Visual Studio 2017/2019 aktualisiert.

Jetzt treten beim Kompilieren einige Fehler im Formular auf:

<source>(13): error C2280: 'OfflineFixture::OfflineFixture(const OfflineFixture &)': attempting to reference a deleted function

<source>(8): note: compiler has generated 'OfflineFixture::OfflineFixture' here

<source>(8): note: 'OfflineFixture::OfflineFixture(const OfflineFixture &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'

Ein eindeutiger Zeiger ist ein Mitglied der Klasse, das keinen Konstruktor und keinen Destruktor hat. In diesem Fall ermöglicht Visual Studio das Instanziieren eines Objekts auf folgende Weise:

OfflineFixture a{};  // works!

Aber mit:

auto&& a = OfflineFixture{};

Gibt oben Kompilierungsfehler.

const auto& a = OfflineFixture{};

Gibt auch oben Kompilierungsfehler.

Bitte schauen Sie hier: https://gcc.godbolt.org/z/XtP40t

Meine Frage lautet: Ist mein Code falsch?

Die angegebenen Beispiele werden kompiliert mit: gcc (9.1 und niedriger) clang Visual Studio 2013

Aber es scheitert in:

  • Visual Studio 2015

  • Visual Studio 2017

  • Visual Studio 2019

Eine Möglichkeit, dies zu beheben, besteht darin, einen Standardkonstruktor in OfflineFixture zu implementieren.

Minimales Beispiel:

#include <memory>

struct OfflineFixture
{
    void x() const {} 
    int i;
    std::unique_ptr<int> m_calc;
};

int test() {

#if 1
    const auto&& a = OfflineFixture{};
#else
    OfflineFixture a{};
#endif
    a.x();

    return 0;
}
4
Gunther 3 Juli 2019 im 12:52

3 Antworten

Beste Antwort

Lassen Sie uns hier einige vorläufige Punkte ansprechen.

Im Allgemeinen lautet die Aussage:

const auto&& a = Foo{};

Ist in C ++ vollkommen legal. Darüber hinaus ist es nicht wahr, dass es sich um undefiniertes Verhalten handelt. Tatsächlich ist dies ein perfektes Beispiel für Referenzinitialisierung mit lebenslanger Verlängerung eines vorübergehenden.

Immer wenn eine Referenz an ein temporäres Objekt oder ein Teilobjekt davon gebunden ist, wird die Lebensdauer des temporären Objekts verlängert, um der Lebensdauer der Referenz zu entsprechen [...].

Es wird mit einigen Ausnahmen fortgesetzt (ich werde nicht alle zitieren), aber die Deklaration eines neuen Objekts ist nicht Teil dieser Ausnahmen.


In Bezug auf Ihre Klasse scheint es klar zu sein, dass das Problem das std::unique_ptr Mitglied ist.

Hier ein minimales Beispiel:

#include <memory>

struct OfflineFixture {
  std::unique_ptr<int> m_calc;
};

void test() {
  const auto&& a = OfflineFixture{};  // <--- Error in msvc
}

Irgendwie versucht MSVC , eine Kopie des Objekts zu erstellen. In der Tat geht es bei dem Fehler um das Aufrufen des Kopierkonstruktors (der aufgrund von std::unique_ptr gelöscht wird).

Da hier keine Kopien durchgeführt werden sollten, scheint es sich um einen msvc -Fehler zu handeln.

Hinweis: gcc und clang lassen sich damit gut kompilieren.

2
Biagio Festa 3 Juli 2019 im 10:40

Ich habe constructor und move constructor hinzugefügt, wie im folgenden Code gezeigt.

Dies behebt das Problem.

struct OfflineFixture
{
    void x() const {} 
    int i;
    std::unique_ptr<int> m_calc;

    OfflineFixture(){}
    OfflineFixture(OfflineFixture &&){}

    //implicit
    OfflineFixture(const OfflineFixture&) = default;
    OfflineFixture& operator=(const OfflineFixture&) = default;
    ~OfflineFixture() = default;

 };

As, const auto&& a = OfflineFixture{}; erfordert constructor und move constructor

Ich hoffe, es hilft!

1
Abhishek Sinha 3 Juli 2019 im 10:07

Es ist interessant festzustellen, dass MSVC dieses fehlerhafte Verhalten nur anzeigt, wenn Sie keinen Konstruktor oder einen Standardkonstruktor angeben:

struct OfflineFixture {
    OfflineFixture()=default;
    //...
};

Das Beispiel kann behoben werden, indem einem Konstruktor ein leerer Block bereitgestellt wird:

struct OfflineFixture {
    OfflineFixture(){}
    //...
};

Was gut kompiliert.

1
Matthias Straka 4 Juli 2019 im 14:40