Frage

Dies ist kein Duplikat von Implementierung des Copykonstruktor in Bezug auf operator = sondern ist eine speziellere Frage. (Oder so Ich mag denken.)

Intro

Bei einer (hypothetischen) Klasse wie folgt:

struct FooBar {
  long id;
  double valX;
  double valZ;
  long   valN;
  bool   flag; 
  NonCopyable implementation_detail; // cannot and must not be copied

  // ...
};

Wir können dies nicht durch die Standard-generierten Funktionen kopieren, weil Sie weder Konstrukt kopieren noch kopieren, um ein NonCopyable Objekt. Doch dieser Teil des Objekts ist eine Implementierung Detail, das wir eigentlich nicht interessiert sind, zu kopieren.

Es tut auch keinen Sinn machen eine Swap-Funktion für diese schreiben , weil der Swap-Funktion kann nur wiederholen, was std :: Swap funktioniert (minus der NonCopyable).

Wenn wir also diese Objekte kopieren wollen, sind wir mit der Umsetzung der Kopie-Ctor und Kopie-Betreiber selbst überlassen. Dies ist trivialerweise getan, indem nur die anderen Mitglieder zuweisen.

Frage

Wenn wir Kopie Ctor und Betreiber implementieren müssen, sollten wir die Kopie Ctor in Bezug auf die Kopie Betreiber implementieren, oder sollten wir „Duplikat“ den Code mit der Initialisierung Liste?

Das heißt, gegeben:

FooBar& operator=(FooBar const& rhs) {
  // no self assignment check necessary
  id = rhs.id;
  valX = rhs.valX;
  valZ = rhs.valZ;
  valN = rhs.valN;
  flag = rhs.flag;
  // don't copy implementation_detail
  return *this;
}

Should schreiben wir a)

FooBar(FooBar const& rhs) {
  *this = rhs;
}

oder b)

FooBar(FooBar const& rhs)
: id(rhs.id)
, valX(rhs.valX)
, valZ(rhs.valZ)
, valN(rhs.valN)
, flag(rhs.flag)
// don't copy implementation_detail
{ }

Mögliche Aspekte für eine Antwort wäre Leistung vs. Wartbarkeit vs. Lesbarkeit.

War es hilfreich?

Lösung

Im Allgemeinen ziehe ich b) über a), wie es ausdrücklich jegliche Standardkonstruktion der Mitglieder vermeidet. Für Ints, Doppel etc., die keine Überlegung ist, aber es kann für die Mitglieder mit teueren Operationen oder Nebenwirkungen. Es ist besser verwaltbar, wenn Sie nicht über diese potenziellen Kosten / Frage zu prüfen haben, wie Sie das Hinzufügen und Entfernen von Mitgliedern. Initialiser Listen auch Referenzen und Nicht-Standard-konstruierbar Elemente unterstützen.

Alternativ können Sie eine Unterstruktur für die Nicht- „Implementierungsdetail“ Mitglieder haben und lassen Sie die Compiler Kopieren Code erzeugen, entlang der Linien:

struct X 
{
    struct I
    {
        int x_;
        int y_;
    } i_;
    int z_;

    X() { }

    X(const X& rhs)
      : i_(rhs.i_), z_(0) // implementation not copied
    { }

    X& operator=(const X& rhs)
    {
        i_ = rhs.i_;
        return *this;
    } 
};

Andere Tipps

Normalerweise Sie Zuweisungsoperator in Bezug auf Copykonstruktor (@Roger Pate-Version) implementieren

FooBar& operator=(FooBar copy) { swap(*this, copy); return *this; }
friend void swap(FooBar &a, FooBar &b) {/*...*/}

Dies erfordert eine swap Funktion bereitstellt, die entsprechenden Mitglieder Swaps (alle außer implementation_detail in Ihrem Fall).

Wenn swap nicht Diesen Ansatz garantiert werfen, dass das Objekt in irgendeine inkonsistenten Zustand nicht verlassen (nur mit einem Teil Mitgliedern zugewiesen).

Doch in Ihrem Fall, da weder Copykonstruktor noch Zuweisungsoperator kann Copykonstruktor in Bezug auf dem Zuweisungsoperators wirft Umsetzung (a) ist auch in Ordnung und ist mehr wartbar dann in beiden Orten fast identischen Code mit (b).

Wenn Sie wirklich gestört zu replizieren std :: swap, warum nicht alles anderes als die Implementierung Detail in eine Struktur setzen?

struct FooBarCore {
  long id;
  double valX;
  double valZ;
  long   valN;
  bool   flag; 
  // ...
};

struct FooBar {
  FooBarCore core_;
  NonCopyable implementation_detail; // cannot and must not be copied
};

, dann können Sie std :: Swap für diese Struktur in der Kopierfunktion für FooBar verwenden.

FooBar& operator=(const FooBar &src) {
  FooBarCore temp(src.core_)
  swap(temp,*this.core_);
  return *this;
}

Okay, noch einmal zu versuchen, basierend auf meinem Kommentar zu dieser Antwort .

Wickeln Sie die implementation_detail in einer kopierbar Klasse:

class ImplementationDetail
{
public:
  ImplementationDetail() {}
  ImplementationDetail(const ImplementationDetail&) {}
  ImplementationDetail& operator=(const ImplementationDetail&) {}

public: // To make the example short
  Uncopyable implementation_detail;
};

und verwenden Sie diese Klasse in Ihrer FooBar. Der Standard erzeugt Copykonstruktor und kopieren Zuweisungsoperator für Foobar ordnungsgemäß funktionieren.

Vielleicht könnte es auch von uncopyable ableiten, so dass Sie alle über Ihren Code nicht implementation_detail.implementation_detail bekommen. Oder wenn Sie den Code in der implementation_detail Klasse steuern, fügen Sie einfach den leeren Copy-Konstruktor und leer Zuweisungsoperator.

Wenn der Copy-Konstruktor nicht kopieren implementation_detail müssen und wird noch richtig sein (ich das letztere zweifeln, aber nehmen wir an, es für den Moment), die implementation_detail ist überflüssig.

So ist die Lösung zu sein scheint. Die implementation_detail statisch zu machen und verlassen sich auf die Standard-generierte Kopierkonstruktor und Zuweisungsoperator

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