Frage

Ich habe kürzlich entdeckt, dass, wenn ich Zeiger innerhalb einer Klasse haben, ich brauche einen Copy-Konstruktor angeben.

Um das zu lernen, habe ich den folgenden einfachen Code. Es kompiliert, sondern gibt mir Laufzeitfehler, wenn die Copykonstruktor durchführen.

Ich versuche nur, den Wert aus dem Zeiger des kopierten Objekts zu kopieren, aber vermeiden die gleiche Adresse zugewiesen wird.

Also, was ist hier los?

    class TRY{
        public:
        TRY();
    ~TRY();
        TRY(TRY const &);

        int *pointer;

        void setPointer(int);
    };


    void TRY::setPointer(int a){
        *pointer = a;

        return;
    }


    TRY::TRY(){}


    TRY::~TRY(){}


    TRY::TRY(TRY const & copyTRY){
        int a = *copyTRY.pointer;
        *pointer = a;
    }



    int main(){

        TRY a;
        a.setPointer(5);

        TRY b = a;

        b.setPointer(8);

        cout << "Address of object a = " << &a << endl;
        cout << "Address of object b = " << &b << endl;

        cout << "Address of a.pointer = " << a.pointer << endl;
        cout << "Address of b.pointer = " << b.pointer << endl;

        cout << "Value in a.pointer = " << *a.pointer << endl;
        cout << "Value in b.pointer = " << *b.pointer << endl;

        return 0;
    }

Ich werde dieses Konzept für andere Klassen mit vielen Zeiger in es verwenden, wo ich auf Objekt zum anderen alle Werte kopieren müssen. Das Kopieren ist zunächst erforderlich, für diesen Code, so möchte ich die Kopier Möglichkeit zu halten (ich will nicht den Kopierkonstruktor als privat versteckt).

Außerdem ist die echte Klasse I implementieren müssen hat wie 10 Zeiger, und es könnte mit der Zeit ändern. Ist das nicht eine etwas intelligentere Weise einen tiefen Copykonstruktor in C ++ haben? ...

War es hilfreich?

Lösung

Mit der Anweisung int* pointer Sie haben nur einen Zeiger definiert, aber jeder Speicher nicht zugewiesen hat. Zuerst sollten Sie es auf einen geeigneten Speicherplatz Punkt machen, indem einige Speicher wie diese Zuteilung: int* pointer = new int. Dann in dem Copykonstruktor wieder müssen Sie den Speicher für das kopierte Objekt zuordnen. Vergessen Sie auch nicht den Speicher freizugeben in dem destructor mit löschen.

Ich hoffe, dass dieses Beispiel hilft:

class B
{

public:
    B();
    B(const B& b);
    ~B();
    void setVal(int val);

private:
    int* m_p;
};

B::B() 
{
    //Allocate the memory to hold an int
    m_p = new int;

    *m_p = 0;
}

B::B(const B& b)
{
    //Allocate the memory first
    m_p = new int;

    //Then copy the value from the passed object
    *m_p = *b.m_p;
}

B::~B()
{

    //Release the memory allocated
    delete m_p;
    m_p = NULL;
}

void B::setVal(int val)
{
    *m_p = val;
}

Andere Tipps

  

Ich habe kürzlich entdeckt, dass, wenn ich   haben Zeiger innerhalb einer Klasse, ich brauche   eine Kopie Konstruktor angeben.

Es ist nicht ganz richtig. Wenn Sie Zeiger in Ihrer Klasse haben und ordnen den Speicher mit new dann müssen Sie über Copykonstruktor kümmern. Vergessen Sie auch nicht den Zuweisungsoperator und destructor. Sie müssen den Speicher löschen delete zugewiesen werden.

Es heißt Law Of The Big Three .

Beispiel:

  ~Matrix();  //Destructor
  Matrix(const Matrix& m); //Copy constructor
  Matrix& operator= (const Matrix& m); //Assignment operator

Wenn Sie eine tiefe Kopie tun möchten, Sie müssen natürlich auch neue Speicher zuweisen, um die Werte zu halten. Wenn das Original einen Zeiger auf einen int hat, und Sie wollen nicht die Kopie desselben Zeigerwert zu verwenden, müssen Sie neue Speicher zuweisen, um einen int zu halten, und dann gibt den Wert kopieren.

Ihr Beispiel ist nicht ganz klar, es ist nicht die Umsetzung Ihrer Copykonstruktor nicht zeigt, oder wie das pointer Mitglied initialisiert wird.

  

Ich habe kürzlich entdeckt, dass, wenn ich   haben Zeiger innerhalb einer Klasse, ich brauche   eine Kopie Konstruktor angeben

Mehr als oft nicht es eine gute Idee ist es, einfach zu deaktivieren, indem sie (und der assigment Operator) private und nicht deren Umsetzung zu erklären.

Wenn es einen Zeiger auf eine regelmäßige Art hat dann

A::A(const A& a):
  pointer_( new int( *a.pointer_ ) )
{
}

Wenn es einen Zeiger auf einige Basisklasse hat dann

A::A(const &a ):
  pointer_( a.pointer_->clone() )
{
}

Klonen ist eine Implementierung eines Urmuster

Vergessen Sie nicht, den Zeiger in dem destructor

löschen
A::~A()
{
    delete pointer_;
}

Ihr Beispiel beheben

TRY::TRY(TRY const & copyTRY){
    int a = *copyTRY.pointer;
    pointer = new int(a);
}

Ihr Problem ist hier in dieser Zeile:

    *pointer = a;

All die Dinge, die normalerweise in Ihrem Standard-Konstruktor passiert ist noch nicht geschehen, einschließlich der Zuweisung von Speicher für *pointer.

Die Lösung ist Speicher für eine ganze Zahl zuzuordnen. Sie können malloc und Freunde oder new für diese, aber stellen Sie sicher, dass es die gleiche Methode, die Sie in Ihrem Standard-Konstruktor verwenden, weil Sie nur eine destructor bekommen, und die Anrufe entsprechen.

Wenn ein Mitglied weise (flache) Kopie in Ordnung ist, dann haben Sie nichts zu tun. Wenn Sie eine tiefe Kopie wollen, müssen Sie Kopien aller Mitglieder neuen Speicher zuweisen.

Wenn Sie eine Kopie Konstruktor schreiben, sollten Sie Speicher für alle Mitglieder zuweisen. In Ihrem Fall:

TRY::TRY(TRY const & copyTRY){
    pointer = new int(*(copyTry.pointer));
}

Operator = ist irgendwie ähnlich, aber ohne Speicherzuweisung.

TRY& operator=(TRY const& otherTRY){
      this->a  = *(otherTry.pointer)
      return *this
}

Mehr als oft nicht, wenn Sie eine Kopie Konstruktor oder Zuweisungsoperator zu schreiben sind Sie etwas falsch zu machen. Lassen Sie die Kopie und Zuweisungs Betreiber die Implementierer der Standardbibliothek. Verfassen Sie Ihre Klassen von bereits kopierbar und zuweisbare Elemente und Sie müssen nicht Ihre eigenen schreiben.

Zum Beispiel, vielleicht int * Mitglied sollte stattdessen ein std :: vector sein.

Wenn Sie nicht die Klasse Standard kopierbar / zuweisbare machen können, vielleicht können Sie es nicht kopierbaren / belegbar, indem er erklärt, nicht aber die Umsetzung, eine private Kopie Konstruktor und Zuweisungsoperator.

Nur wenn keine der oben genannten sind möglich, sollten Sie Ihre eigene Kopie Konstruktor oder Zuweisungsoperator implementieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top