Ich gebe eine Antwort mehr aus der modernen C++ Perspektive von "vermeiden Sie rohe Zeiger, wenn Sie können". Aber ich werde auch eine wichtige Unterscheidung weisen darauf hin, sollten Sie sich bewusst sein:
C++ constructor syntax
Aber lassen Sie uns zuerst überlegen, was Ihre Absicht ist. Wenn ich schrieb:
Sample x = 1;
Sample y = x;
Was sollte die Semantik sein?
Sollten die Sample
„Kopien“ haben jeweils ihre eigenen, unabhängigen ‚ptr‘, dessen Spitz zu Lebensdauer Objekt nur so lange, wie die Klasse hält sie in der sie leben?
Es ist in der Regel der Fall, dass Sie Zeiger überhaupt nicht benötigen, wenn dies das ist, was Sie wollen.
Die meiste Zeit, die gesamte Klassengröße wird genug, dass Stack Zuteilung ein Problem sein wird nicht sinnvoll sein, wenn man sie für sich beanspruchen, ohne new
(wie Sie hier sind). Warum also Zeiger einbeziehen? Verwenden Sie einfach int i
(oder was auch immer Ihre nicht-POD Klasse ist).
Wenn Sie tatsächlich die Art der Fall, wo Sie Notwendigkeit tun dynamisch zu große Datenblöcke zuweisen, um sich zu verwalten (gegen Aufschieben zu C++ Bibliothek Sammlungen oder ähnliches), konnten die exceed your stack. Wenn Sie dynamisch zuordnen müssen, müssen Sie die Konstruktion auf die eine oder andere Weise kopieren. Das bedeutet Sample
muss explizit die Kopie Konstruktion verwalten -oder- verwenden Sie eine smart pointer Klasse, die es so verfeinert, dass es nicht muss.
Zunächst lassen Sie uns sagen Sie den Rohzeiger zu halten sind, das würde bedeuten:
Sample(const Sample & other)
{
ptr = new int(*other.ptr);
}
ABER könnten Sie das Potenzial für Fehler in dieser Situation zu reduzieren, indem eine unique_ptr
stattdessen verwenden. Ein unique_ptr zerstört die Daten, auf die der rohe Zeiger zeigt, der automatisch gehalten wird, wenn der Destruktor ausgeführt wird. Sie müssen sich also nicht darum kümmern, delete
anzurufen.
Auch, eine unique_ptr wird standardmäßig nicht kopieren. Also, wenn Sie nur geschrieben haben:
Die Klasse selbst kann bauen, aber Sie würden Fehler bei Ihren Callsites bekommen. Sie würden darauf hinweisen, dass Sie Kopien für etwas erstellen, für das die Kopierkonstruktion nicht richtig definiert wurde. Nicht nur das...Sie sind nicht nur machen ein Kopie in Ihrem Programm, aber zwei:
In function ‘int main()’:
error: use of deleted function ‘Sample::Sample(const Sample&)’
Sample s1 = 10;
^
note: ‘Sample::Sample(const Sample&)’ is implicitly deleted
because the default definition would be ill-formed:
error: use of deleted function ‘Sample::Sample(const Sample&)’
SomeFunc(s1);
^
, dass Sie ein Heads-up gibt einen Kopierkonstruktor entspricht hinzuzufügen:
Sample(const Sample & other)
{
ptr = std::unique_ptr<int>(new int(*other.ptr));
}
Und Sie wahrscheinlich möchte Sample s1 = 10;
zu Sample s1 (10);
ändern, um die Kopie dort zu vermeiden. In diesem Fall könnten Sie auch wollen, dass SomeFunc
seine Werte als Referenz verwendet. Ich erwähne auch die Suche in initializer lists vs assignments.
. (Anmerkung: Es gibt tatsächlich einen Namen für das Muster einer Smart-Pointer-Klasse, die Kopien clone_ptr
genannt, so würden Sie nicht schreiben müssen auch dass Copykonstruktor Es ist nicht in der Standard-C++ Bibliothek aber you'll find implementations around.)
Sollen die Sample
„Kopien“ ein gemeinsames dynamischen ptr
, die erst nach dem letzten Verweise weggeht gelöscht wird?
Leichter mit intelligenten Zeigern, und kein Kopierkonstruktor für Sample erforderlich. Verwenden Sie eine shared_ptr
. Das Standardverhalten von shared_ptr soll mit einfachen Zuweisungen kopiert werden können.
class Sample
{
public:
shared_ptr<int> ptr;
Sample(int i)
{
ptr = make_shared<int>(i);
}
~Sample()
{
cout << "destroyed";
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
Moral der Geschichte ist, dass desto mehr können Sie die Standardverhalten tun, um die richtige Arbeit für Sie lassen ... und desto weniger Code, den Sie schreiben ... desto weniger Potenzial haben Sie für Fehler. Es ist also gut zu wissen, was Kopierkonstrukteure machen und wann sie aufgerufen werden, aber es kann genauso wichtig sein, zu wissen, wie man sie schreibt und schreibt. nicht!
Beachten Sie, dass unique_ptr und shared_ptr aus C++ 11 stammen und #include <memory>
benötigen.
Wissen Sie, was Pass by Referenz bedeutet? – doctorlove
gutes Beispiel dafür, warum Kopierkonstruktoren nützlich sind –
@Claptrap Ein gutes Beispiel dafür, warum Sie nicht selbst mit dem Speicher umgehen sollten und einen intelligenten Zeiger dazu bringen sollten. Besser als die Regel von drei/fünf ist die [** Regel von Null **] (http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html) – JBL