What's the Best Signature for Clone() in C++

What's the best signature for clone() in C++?

It depends on your use case. If you ever think you will need to call clone on a derived object whose dynamic type you know (remember, the whole point of clone is to allow copying without knowing the dynamic type), then you should probably return a dumb pointer and load that into a smart pointer in the calling code. If not, then you only need to return a smart_ptr and so you can feel free to return it in all overrides.

(C++) How to write a clone method for a class which has a unique pointer as a data member?

Simply add a copy constructor to DecoratedDerived that clone()'s the data member, eg:

class DecoratedDerived : public Base {
private:
unique_ptr<Base> ptr;
// ...
public:
DecoratedDerived(const DecoratedDerived &src)
: Base(src), ptr(src.ptr ? src.ptr->clone() : nullptr)
{
}

// ...

DecoratedDerived* clone() const override{
return new DecoratedDerived(*this);
}
};

Online Demo

Looking for a design pattern to apply in C++

Implement a clone() method in B.

Pass a B* to A when creating it. A will call B's clone() with that B* as a parameter.

For further information about cloning see questions Which situation will use clone in C++ and how to use it?, What's the best signature for clone() in C++? and How to write a clone method easily?, among others.

Covariant clone function misunderstanding

The declaration

auto funky = bp->clone();

is equivalent to

Base* funky = bp->clone();

since Base::clone returns a Base*.

Checking the type of that pointer then yields Base*.

Checking the type of the pointee is a different matter, when the Base type is polymorphic. And in the presented code Base is polymorphic because clone is virtual. To understand more of this functionality, check the type of the pointee instead of just the type of the pointer.

Usefulness of covariant return types in C++ clone idiom?

It's useful when you have a pointer to Derived and want to get a clone of it:

Derived *ptr = ...;
Derived *clone = ptr->clone();

without covariant return types you must do an explicit cast:

Derived *clone2 = (Derived*)ptr->clone();

Note that Derived may be a base class for even more derived classes, in that case it makes even more sense.

Unfortunately auto_ptr<Derived> and auto_ptr<Base> are not covariant. So you must return the same type from all clone functions in that case.

Copy constructor's signature without reference

Point(const Point p)

Why is it considered as copy constructor, instead of a constructor?

It's not.

As the standard says in §12.8/2:

A non-template constructor for class X is a copy constructor if its
first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other
parameters have default arguments (...).

In fact, your declaration is ill-formed. §12.8/6 says:

A declaration of a constructor for a class X is ill-formed if its
first parameter is of type (optionally cv-qualified) X and either
there are no other parameters or else all other parameters have
default arguments.

You do have exactly that: a constructor for a class Point whose first parameter is of type const Point and there are no other arguments.

This is of course the formal explanation. As others have explained, the practical implication of such a constructor would be infinite recursion.

Perhaps you are concerned about the error message you got. However, there are absolutely no rules regarding the contents of a diagnostic message produced by a compiler. It's a quality-of-implementation issue; if your compiler thinks that copy constructor for class "Point" may not have a parameter of type "Point" is a good way to convey the problem to its users, then so be it.

C#: Force constructor signature using abstract class?

You could write a ReSharper plugin that recognises this case and highlights the class if it doesn't have a "copy constructor". This would be a daemon stage that would process the file as it's being edited, and add highlights. You can look through the abstract syntax tree of the file, look for all instances of IConstructorDeclaration, and then get the constructor's parameters from the ParameterDeclarations property. You can check that there is a constructor that only has one parameter, and that parameter is the same type as the class it's declared in.

You can compare the types by getting the constructor's parameter's TypeUsage and trying to downcast to IUserTypeUsage. You can then use ScalarTypeName.Reference.Resolve() to get an instance of IDeclaredElement. Compare this against the class's IClassDeclaration.DeclaredElement to see if they're the same instance.

Deep cloning objects

Whereas one approach is to implement the ICloneable interface (described here, so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it into our code.
As mentioned elsewhere, it requires your objects to be serializable.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
/// <summary>
/// Perform a deep copy of the object via serialization.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>A deep copy of the object.</returns>
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(source));
}

// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null)) return default;

using var Stream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}

The idea is that it serializes your object and then deserializes it into a fresh object. The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

In case of you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:

public static T Clone<T>(this T source)
{
// ...
}

Now the method call simply becomes objectBeingCloned.Clone();.

EDIT (January 10 2015) Thought I'd revisit this, to mention I recently started using (Newtonsoft) Json to do this, it should be lighter, and avoids the overhead of [Serializable] tags. (NB @atconway has pointed out in the comments that private members are not cloned using the JSON method)

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialization method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null)) return default;

// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}


Related Topics



Leave a reply



Submit