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?
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.
10124200cookie-checkKann eine Klasse mit einem konstanten Datenelement in C++ keinen Kopierzuweisungsoperator haben?yes
Es ist im Allgemeinen ein Fehler für a
class
Ein … Habenconst
Datenelement. Es ist normalerweise besser, die Konstanz zu garantieren, indem man es machtprivate
und keinen Setter bereitzustellen. Es ist schwächer alsconst
aber der Kompromiss neigt sich normalerweise zugunsten der Nichtverwendungconst
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önnenk
. 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 nichtconst
. Es gibt keinen Mittelweg. Wenn Sie in der Lage sein müssen, es zu ändern, sollte es nicht markiert werdenconst
.– Peter Becker
5. März 2020 um 15:04 Uhr