Use of the Implicit Copy Constructor in User-Defined Copy Constructor
Asked Answered
I

3

6

I have a rather large and lengthy class where the implicitly generated copy-constructor would almost do exactly the right thing, except for one specific field.

Is there a way to write a user-defined copy-constructor that calls the implicit version, and then adds one or two lines at the end? Or do I have to write a lengthy, (and boring, and typo-prone) user-defined copy-constructor that mostly duplicates the implicit one?

class MySimpleObject
{
private:
   FieldA m_fieldA;
   FieldB m_fieldB;
   [... repeated a lot...]
   SpecialField m_trickyField;

public:
    MySimpleObject(const MySimpleObject& other)
    {
        ImplicitCopyCtor(*this,other); // This is what I want to simplify, instead of copying all the fields by hand.

        m_trickyField.DoCloneSeparately(other.m_trickyField);
    }
};

Note: SpecialField is provided by a 3rd party library, so I cannot refactor it or modify it. I don't know why it doesn't copy properly, but it doesn't, and I assume there's a good reason. I like the idea of wrapping it inside a class that will behave properly. I'll look into that.

Inarch answered 22/8, 2016 at 21:50 Comment(10)
refactor trickyfield so that it does the right thing.Duisburg
It is not possible in this case to refactor m_trickyField. It is provided by a 3rd party.Inarch
@πάνταῥεῖ It's quite a clear bit of exposition, I'd say.Zendavesta
Give SpecialField proper copy semantics. Then the implicit copy constructor will work.Guertin
@Inarch so wrap m_trickyField in some other type.Effusion
@πάνταῥεῖ: Must be! He's trying to delegate to the implicitly-defined constructor. Can't do that, of course.Zendavesta
@LightnessRacesinOrbit Such like an inner private class doing the actual copy?Gerstein
@πάνταῥεῖ, read the question: "Is there a way to write a user-defined copy-constructor that calls the implicit version, and then adds one or two lines at the end?" That's what the code is trying to do. That syntax is close to something that works in Java.Effusion
@πάνταῥεῖ: That might work yeahZendavesta
@JonathanWakely That's not possible as we all know, so I missed what ImplicitCopyCtor type should be.Gerstein
E
17

The fundamental theorem of software engineering is your friend:

struct MakeSpecialSnowflakeLessSpecial
{
  MakeSpecialSnowflakeLessSpecial(const MakeSpecialSnowflakeLessSpecial& other)
  {
    m_trickyField.DoCloneSeparately(other.m_trickyField);
  }

  SpecialField m_trickyField;
};


class MySimpleObject
{
private:
   FieldA m_fieldA;
   FieldB m_fieldB;
   [... repeated a lot...]
   MakeSpecialSnowflakeLessSpecial m_special;

public:
    MySimpleObject(const MySimpleObject&) = default;
};
Effusion answered 22/8, 2016 at 21:57 Comment(1)
I also love that the exposition of the fundamental theorem itself has two layers of indirection...Preconceive
Z
4

No, there is not.

Your best bet is to fix the problematic member.

A quick solution might be to wrap it in a class that unbreaks its copy semantics.

Zendavesta answered 22/8, 2016 at 21:54 Comment(0)
M
2

There are two solutions to your problem, that I can think of:

  1. Put the normal stuff into an extra struct that you inherit from privately.
  2. Wrap the type of your field, that needs special treatment into an other type to implement the required copy-semantics there.

The first solution would look like this:

struct MySimpleObjectDefaultData
{
    FieldA m_fieldA;
    FieldB m_fieldB;
   // [... repeated a lot...]
}

class MySimpleObject : private MySimpleObjectDefaultData
{
private:
   SpecialField m_trickyField;

public:
    MySimpleObject(const MySimpleObject& other)
        : MySimpleObjectDefaultData( other )
    {
        m_trickyField.DoCloneSeparately(other.m_trickyField);
    }
};

This is less invasive for the rest of your code, since the access rights and the types of the fields stay exactly the same. You will not need to touch the rest of your existing code, to make this solution work. Also, this solution is a bit more generic, since you can actually apply any post-processing steps to the compiler-generated copy constructor manually.

The second would look like this:

struct SpecialFieldWrapper : SpecialField
{
    using SpecialField::SpecialField;

    SpecialFieldWrapper( const SpecialFieldWrapper & other )
    {
        DoCloneSeparately( other.m_trickyField );
    }
};

class MySimpleObject
{
private:
   FieldA m_fieldA;
   FieldB m_fieldB;
   [... repeated a lot...]
   SpecialFieldWrapper m_trickyField;

public:
    MySimpleObject(const MySimpleObject& other)
    {
        ImplicitCopyCtor(*this,other); // This is what I want to simplify, instead of copying all the fields by hand.

        m_trickyField.DoCloneSeparately(other.m_trickyField);
    }
};

This solution may be easier to read than the first. However, types change slightly and this can make further changes to your code necessary.

Manciple answered 23/8, 2016 at 7:15 Comment(1)
I do like your first solution. Creating a base-class for all the "normal" fields works very nicely!Inarch

© 2022 - 2024 — McMap. All rights reserved.