$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
Very cool. Looks like a good way to pass hints to the copy constructor. Some example situations I can think of where this might be useful:
Copying a data structure where the copy will then be populated with additional data
The additional parameter would hint at the likely soon -to-be-needed capacity to optimize allocation. The default capacity would be a sentinel value to indicate just use the default capacity or the capacity of the original data structure.
Whether to do a deep copy or shallow copy of member values
The default might be to do a deep copy for safety, but advanced uses could take advantage of specifying rare occasions of when its safe to do a shallow copy.
Verbatim copy vs logical copy
Hint whether the data structure's copy constructor should copy the original data structure's internal structure verbatim or whether its safe to optimize or consolidate it. For example, the hint could indicate a tree should be balanced as it is copied.
The old std::basic_string
does have one too:
basic_string(const basic_string& s,
size_type pos = 0, size_type n = npos)
I have a situation where I require the copy constructor to have more than one parameter in one of my class involving deep copy.
Basically the problem is that an object contains another object that need to keep track of it through a pointer, but a normal deep copy would only copy the pointer value and not the correct memory location of the new object.
By disabling the normal copy constructor and using the variant with two parameters I'm able to deep copy correctly my object.
[Edit]: looking through my code it seems that it is even more common than I though as I use it at a couple of place elsewhere too.
Here is a code sample for the curious (this is a simplified version and is actually a little more complicated)
//-----------------------------------------------------------------------------
scan_point::scan_point(scan_point const& rhs, simulation* sim_)
: m(rhs.m), sim(sim_)
//-----------------------------------------------------------------------------
{
}
--
simulation_(simulation_ const& rhs)
{
//...
for(typename ContainerType::const_iterator it = rhs.spContainer->begin(), endIt = rhs.spContainer->end();
it != endIt; it++)
{
spContainer->push_back(new scan_point(*it, this));
}
}
--
To makes things less painful during copy I use smart_ptr class that allow deep copy and (in this case specifically) embed my members in a struct to makes the compiler auto-generate the copying for about all other members (see for a try to a short example: https://stackoverflow.com/questions/469696/what-is-your-most-useful-c-c-utility/1609496#1609496).
The BDE allocator [PDF Link] used this quirk. For example their array allocator looked like this:
template <typename T>
class bde::Array {
public:
Array(bde::Allocator *allocator = 0);
Array(const Array &rhs, bde::Allocator *allocator = 0);
};