Kann eine Klasse mit einem konstanten Datenelement in C++ keinen Kopierzuweisungsoperator haben?

Lesezeit: 4 Minuten

Ich entwerfe eine Klasse, die ein konstantes Datenelement namens haben sollte K. Ich möchte auch, dass diese Klasse einen Kopierzuweisungsoperator hat, aber der Compiler scheint den Kopierzuweisungsoperator implizit aus jeder Klasse mit konstanten Datenmitgliedern zu löschen. Dieser Code veranschaulicht das wesentliche Problem:

class A
{
    private:
       const int K;
    public:
       A(int k) : K(k) {} // constructor
       A() = delete; // delete default constructor, since we have to set K at initialization

       A & operator=(A const & in) { K = in.K; } // copy assignment operator that generates the error below
}

Hier ist der Fehler, der generiert wird:

constructor.cpp:13:35: error: cannot assign to non-static data member 'K' with const- 
qualified type 'const int'
            A & operator=(A const & in) { K = in.K; }
                                          ~ ^
constructor.cpp:6:13: note: non-static data member 'K' declared const here
            const int K;
            ~~~~~~~~~~^
1 error generated.

Ich glaube, ich verstehe, warum der Compiler das tut; Die Instanz der Klasse, in die ich kopieren möchte, muss existieren, bevor sie kopiert werden kann, und ich kann ihr nichts zuweisen K in dieser Zielinstanz, wenn es const ist, wie ich es oben versuche.

Ist mein Verständnis dieses Problems richtig? Und wenn ja, gibt es eine Möglichkeit, dieses Problem zu umgehen? Das heißt, ich kann einen Kopierkonstruktor für meine Klasse definieren und trotzdem geben K const-ähnlicher Schutz?

  • Es ist im Allgemeinen ein Fehler für a class Ein … Haben const Datenelement. Es ist normalerweise besser, die Konstanz zu garantieren, indem man es macht private und keinen Setter bereitzustellen. Es ist schwächer als const aber der Kompromiss neigt sich normalerweise zugunsten der Nichtverwendung const hier.

    – Francois Andrieux

    4. März 2020 um 21:43 Uhr


  • “kann ich einen Kopierkonstruktor für meine Klasse definieren” Ein Kopierkonstruktor ist einfach zu implementieren, ein Zuweisungsoperator jedoch nicht. Es liegt an Ihnen, zu entscheiden, was es bedeutet, a zuzuweisen A ohne sich ändern zu können k. Sie werden wahrscheinlich feststellen, dass es keinen Sinn macht, was bedeutet, dass es keinen Sinn macht, zu versuchen, den Operator zu implementieren.

    – Francois Andrieux

    4. März 2020 um 21:46 Uhr


  • Wenn Sie darüber nachdenken, wird ein Objekt konstruiert und seine const-Variable wird zum allerersten Mal bei der Erstellung initialisiert, das ist alles schön und gut. Jetzt ist es an der Zeit, es einem anderen Objekt zuzuweisen. An diesem Punkt können Sie die const-Elementdaten keinem anderen Wert zuweisen und die Definition von const verletzen.

    – noobius

    4. März 2020 um 21:57 Uhr

  • ‘K’ sollte entweder sein const oder nicht const. Es gibt keinen Mittelweg. Wenn Sie in der Lage sein müssen, es zu ändern, sollte es nicht markiert werden const.

    – Peter Becker

    5. März 2020 um 15:04 Uhr

In C++ ist eine Klasse mit a const Das Datenelement kann einen Kopierkonstruktor haben.

#include <iostream>

class A
{
private:
    const int k_;
public:
    A(int k) : k_(k) {}
    A() = delete;
    A(const A& other) : k_(other.k_) {}

    int get_k() const { return k_; }
};

int main(int argc, char** argv)
{
    A a1(5);
    A a2(a1);

    std::cout << "a1.k_ = " << a1.get_k() << "\n";
    std::cout << "a2.k_ = " << a2.get_k() << "\n";
}

Ausgabe:

a1.k_ = 5
a2.k_ = 5

In C++ ist eine Klasse mit a const Das Datenelement verwendet möglicherweise nicht den Standardzuweisungsoperator.

class A
{
private:
    const int k_;
public:
    A(int k) : k_(k) {}
    A() = delete;
    A(const A& other) : k_(other.k_) {}

    int get_k() const { return k_; }
};

int main(int argc, char** argv)
{
    A a1(5);
    A a2(0);

    a2 = a1;
}

Ergibt einen Kompilierzeitfehler:

const_copy_constructor.cpp: In function ‘int main(int, char**)’:
const_copy_constructor.cpp:18:10: error: use of deleted function ‘A& A::operator=(const A&)’
   18 |     a2 = a1;
      |          ^~
const_copy_constructor.cpp:1:7: note: ‘A& A::operator=(const A&)’ is implicitly deleted because the default definition would be ill-formed:
    1 | class A
      |       ^
const_copy_constructor.cpp:1:7: error: non-static const member ‘const int A::k_’, can’t use default assignment operator

In C++ ist eine Klasse mit a const Das Datenelement kann einen nicht standardmäßigen Zuweisungsoperator verwenden, solange Sie nicht versuchen, das zu ändern const data-Member, aber Sie denken besser lange und gründlich darüber nach, was es bedeutet, diesen Zuweisungsoperator zu verwenden, wenn eines der zugrunde liegenden Mitglieder nicht geändert werden kann.

class A
{
private:
    const int k_;
public:
    A(int k) : k_(k) {}
    A() = delete;
    A(const A& other) : k_(other.k_) {}

    A& operator=(A const& other)
    {
        // do nothing
        return *this;
    }

    int get_k() const { return k_; }
};

int main(int argc, char** argv)
{
    A a1(5);
    A a2(0);

    a2 = a1;
}

Ergibt keine Kompilierzeitfehler.

Ab c++20 können Sie jetzt Objekte kopieren, die ein oder mehrere konstante Member-Objekte haben, indem Sie Ihren eigenen Kopierzuweisungsoperator definieren.

class A
{
private:
    const int K;
public:
    A(int k) : K(k) {} // constructor
    A() = delete; // delete default constructor, since we have to set K at initialization
    // valid copy assignment operator in >= c++20
    A& operator=(A const& in) {
        if (this != &in)
        {
            std::destroy_at(this);
            std::construct_at(this, in);
        }
    }
};

Möglich wurde dies durch Änderungen in basic.life was das transparente Ersetzen von Objekten, einschließlich derjenigen, die const-Unterobjekte enthalten, ohne UB ermöglicht.

1012420cookie-checkKann eine Klasse mit einem konstanten Datenelement in C++ keinen Kopierzuweisungsoperator haben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy