const auto && really not useful? - c++

Here
https://youtu.be/dTeKf5Oek2c?t=2939
Stephen T. Lavavej says in a talk that const auto && is not useful.
Isn't the following a valid use case?
NonMovableNonCopyable create () {
// ...
return {};
}
const auto && obj = create ();
Concrete application: In XLL code, MS Excel generally does not like its xlopers to be copied or moved which it returns, since after copying or moving it will not be able to correctly free them.

Instead of
const auto && obj = create ();
... write just
const auto object = create();
... or
const auto object{ create() };
The = relies on the compiler eliding the copy constructor call, but I don't know about any extant compiler that fails to do that.
The clarity gained is IMO much more important than the guarantee offered by the reference (and if using reference, do use an ordinary & reference). Namely, one avoids having a maintenance programmer wasting time on trying to understand the rationale for the reference. If the type was explicitly specified it could be a case of polymorphic reference, Petru Marginean's trick, but with auto that's out of the question, and so the maintenance programmers are left scratching their heads, for some period of paid time.
On the other hand, const T&& can be useful for function overloading as an argument type to catch the case of a temporary as argument, in the same way as && qualifier for member function was considered sufficiently useful to be adopted in the standard. For example, even though I do not recommend this, if a pointer to the actual argument is stored for later use, then presumably one doesn't want to store a pointer to a temporary, which will end up as a dangling pointer:
struct Expr{ virtual ~Expr(){} };
struct Sum_expr: Expr
{
const Expr* a_;
const Expr* b_;
Sum_expr( Expr const& a,Expr const& b ): a_( &a ), b_( &b ) {}
template< class A >
Sum_expr( A&&, Expr const&& b ) = delete;
template< class B >
Sum_expr( Expr const&& a, B&& ) = delete;
};
auto main()
-> int
{
Expr a;
Expr b;
Sum_expr sum{ a, b };
Sum_expr sum2{ a, Expr() }; //! Nope, won't compile.
}
Note: Here A&& and B&& support both rvalue and lvalue actual arguments, i.e. they're not necessarily rvalue references, because they're universal references.
But instead of overloading and differentiating the cases I think I'd make that formal argument a pointer, even if a pointer technically can be a nullpointer, because as I see it, with what I'm accustomed to, it communicates the intent more clearly.
Sum_expr( Expr const* a, Expr const* b );

Const T && is very useful if T has a mutable field. A common example is a bool m_movedFrom that's initialized to false and gets set to true when moved from. This allows the rest of your object - resource handle, for example - to remain const.
class Resource // use this as a base class of const correct classes
{
private:
mutable bool m_movedFrom;
protected:
Resource()
: m_movedFrom(false)
{
}
Resource(const Resource&& other)
: m_movedFrom(false)
{
other.m_movedFrom = true;
}
bool isOwning() const // call from descendant's destructor
{
return m_movedFrom;
}
};
EDIT: a more complicated example explaining when the object is itself const, but a global state is not (not claiming this is the good way to solve this, it's for illustrational purposes only):
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
typedef std::string object_type;
typedef std::string seek_type;
class GoalSeeker
{
private:
static std::vector<const GoalSeeker*> s_store;
const std::vector<const GoalSeeker*>::iterator m_iter;
const object_type m_data;
public:
GoalSeeker( const object_type& data )
: m_iter( s_store.insert( s_store.end(), this ) ), m_data(data)
{
}
GoalSeeker( const GoalSeeker& ) = delete;
GoalSeeker( const GoalSeeker&& other )
: m_iter( other.m_iter ), m_data( other.m_data )
{
*m_iter = this;
}
~GoalSeeker()
{
if( *m_iter == this )
{
// cleanup m_data
}
}
static bool seek( const seek_type& needle )
{
return std::find_if(s_store.begin(), s_store.end(),
[&needle](const GoalSeeker* haystack)
{
return haystack->m_data.find(needle) != std::string::npos;
}) != s_store.end();
}
};
std::vector<const GoalSeeker*> GoalSeeker::s_store = {};
GoalSeeker fn()
{
return GoalSeeker("def");
}
int main() {
GoalSeeker a( "abc" );
GoalSeeker b( "cde" );
GoalSeeker s( (const GoalSeeker&&) fn() );
std::cout << GoalSeeker::seek( "de" ) << " " << GoalSeeker::seek( "fff" );
}

Related

Applying C++11 move semantics to bound functions

I have some existing C++98 code that makes use of boost::function and boost:bind for asynchronous callbacks. Some relevant simplified fragments of the code include:
typedef boost::function<void (boost::system::error_code, size_t)> WriteHandler;
struct WriteOperation
{
WriteOperation(const boost::shared_ptr<IDevice>& device,
const std::string& data, const WriteHandler& handler)
: m_Device(device), m_Data(data), m_Handler(handler) {}
private:
boost::shared_ptr<IDevice> m_Device;
std::string m_Data;
WriteHandler m_Handler;
void Complete()
{
boost::system::error_code ec;
size_t len;
...
Async::Post(boost::bind(m_Handler, ec, len));
}
};
struct Device : public IDevice
{
void Write(const std::string& data, const WriteHandler& callback)
{
...
Async::Start(new WriteOperation(shared_from_this(), data,
boost::bind(&Device::HandleWrite, this, handler, _1, _2)));
}
private:
void HandleWrite(const WriteHandler& callback,
boost::system::error_code ec, size_t len)
{
...
callback(ec, len);
}
};
There is one required copy, when constructing the WriteOperation, but other than that I'm trying to avoid copies since they can be quite expensive.
I'm pondering how this should best be written in the C++11 world. The obvious low-hanging fruit is that the WriteOperation constructor internally copies its arguments to its fields, so should use the automatic copying idiom:
WriteOperation(boost::shared_ptr<IDevice> device,
std::string data, WriteHandler handler)
: m_Device(std::move(device)), m_Data(std::move(data)), m_Handler(std::move(handler))
{}
(And of course the bare new should be replaced with unique_ptr, but that's a side issue.)
However I don't think this actually gains anything given the current implementation of Device::Write, so that ought to change too. My problem is that I don't really see a good way to do it. According to this advice, I have three options:
Declare multiple overloads (one with const& and one with &&) -- but since this has two parameters, both of which could benefit from move semantics, this would require four overloads -- getting exponentially worse for methods with more parameters. Additionally this leads to either code duplication or scattering the code over additional methods, which can impair readability.
Pass by value and move (similar to the WriteOperation constructor). This is perhaps the cleanest option when the body always makes a copy, which is true if the WriteOperation constructor is actually called, but what if the elided section contains logic that might return without constructing a WriteOperation? There's a wasted copy in this case.
Template and perfect forward. This requires an ugly SFINAE hack that confuses Intellisense and impairs readability (or worse, leaving the parameter type unconstrained), and requires that the implementation be put into the header, which is sometimes undesirable. And it interferes with type conversions, eg. a SFINAE enable_if is_same looking for std::string will not accept a const char * literal, while the original const& version will.
Am I missing something? Is there a better solution? Or is this just a case where move semantics don't make any difference?
A related case:
typedef boost::function<void (boost::system::error_code, const std::string&)> ReadHandler;
void Read(const ReadHandler& callback)
{
... boost::bind(&Device::HandleRead, this, callback, _1, _2) ...
}
void HandleRead(const ReadHandler& callback,
boost::system::error_code ec, const std::string& data)
{
...
callback(ec, data);
}
This all seems like it should be ok, with no copying and no need for move semantics. And yet again I'm unsure about the ReadHandler passed to Read.
In rough order:
If copy is just as expensive as move, take it by const&.
If you reliably keep a copy, and move is cheap, take by value.
Failing that, you can stuff it in a header and are ok with sfinae or unconstrained templates, use forwarding references.
Failing that, if there are a limited number of arguments, write each overload. This is 2^n in the number of parameters, so there better not be too many. Forward internally to a forwarding reference based implementation.
Failing that, do you really need efficiency here?
Failing that, type erase to "creator of T".
template<class T, using Base=std::function<T()>>
struct creator_of: Base
{
template<class U,
std::enable_if_t<std::is_constructible<T, U&&>{},int> =0
>
creator_of(U&&u):
Base([&]()->T{ return std::forward<U>(u); })
{}
template<class U,
std::enable_if_t<std::is_constructible<T, std::result_of_t<std::decay_t<U>()>{},int> =0
>
creator_of(U&&u):
Base(std::forward<U>(u))
{}
creator_of(creator_of&&)=default;
creator_of():
Base([]()->T{return {};}}
{}
};
augment as needed. A creator_of<std::string> can be constructed from things that can construct a std::string, or from a function object returning a std::string.
Internally you can call () once on it.
(Code not compiled, but design is sound.)
To avoid the combinatorial explosion, while supporting the case where it turns out inside the called function that no argument copies are needed, you can defer the copying.
That's effectively a lazy evaluation scheme, but for this special case only.
With a support class like the one below one needs to be keenly aware that an instance might just hold a pointer to a short-lived caller's object. I.e., don't move a Lazy_copy_ into storage that outlives the call.
#include <iostream>
#include <new>
#include <string> // std::string
#include <utility> // std::move, std::forward
using namespace std;
//------------------------------------ Machinery:
#ifdef TRACE
inline void trace( string const& s )
{
clog << ": " << s << endl;
}
#else
inline void trace( string const& ) {}
#endif
struct Emplace {};
template< class Item >
class Lazy_copy_
{
private:
Item const* p_callers_item_;
union{ Item item_copy_; }; // Left uninitialized if p_callers_item_.
void ensure_is_copy()
{
if( p_callers_item_ )
{
::new( &item_copy_ ) Item( *p_callers_item_ );
trace( "ensure_is_copy: made copy" );
p_callers_item_ = nullptr;
}
}
public:
auto item() const
-> Item const&
{ return (p_callers_item_? *p_callers_item_ : item_copy_); }
auto item_copy()
-> Item&
{
ensure_is_copy();
return item_copy_;
}
~Lazy_copy_()
{
if( not p_callers_item_ ) { item_copy_.Item::~Item(); }
}
Lazy_copy_( Lazy_copy_ const& other )
: p_callers_item_( other.p_callers_item_ )
{
if( p_callers_item_ )
{
ensure_is_copy();
}
else
{
::new( &item_copy_ ) Item( other.item_copy_ );
trace( "<init>( Lazy_copy ): made copy" );
}
}
Lazy_copy_( Lazy_copy_&& other )
: p_callers_item_( other.p_callers_item_ )
{
if( not p_callers_item_ )
{
::new( &item_copy_ ) Item( move( other.item_copy_ ) );
trace( "<init>( Lazy_copy&& ): moved" );
}
}
Lazy_copy_( Item const& item )
: p_callers_item_( &item )
{}
Lazy_copy_( Item&& temp_item )
: p_callers_item_( nullptr )
, item_copy_( move( temp_item ) )
{
trace( "<init>( Item&& ): moved" );
}
template< class... Args >
Lazy_copy_( Emplace, Args&&... args )
: p_callers_item_( nullptr )
, item_copy_( forward<Args>( args )... )
{
trace( "<init>( Emplace, Args... ): Created item from constructor args" );
}
};
//------------------------------------ Example usage:
struct Thingy
{
string a, b, c;
void foo(
Lazy_copy_<string> arg_one,
Lazy_copy_<string> arg_two,
Lazy_copy_<string> arg_three
)
{
if( arg_one.item() == "no_copy" )
{
return; // The case of no copying needed.
}
a = move( arg_one.item_copy() );
b = move( arg_two.item_copy() );
c = move( arg_three.item_copy() );
}
};
auto main()
-> int
{
Thingy x;
string a = "A", b = "B", c = "C";
trace( "Call with copying:" );
x.foo( string( "a" ), b, c );
trace( "" );
trace( "Call without copying: " );
x.foo( string( "no_copy" ), b, c );
}
Output when built with TRACE defined:
: Call with copying:
: <init>( Item&& ): moved
: ensure_is_copy: made copy
: ensure_is_copy: made copy
:
: Call without copying:
: <init>( Item&& ): moved

Selecting between two constructors

Problem: I have a non-copyable object with two constructors. I need to create an object with one of the constructors and then use it within some common code:-
With a copyable object it would look like this, and be easy:
Object a;
if (condition)
a = Object(p1);
else
a = Object(p2,p3,p4);
a.doSomething();
But, the object is non-copyable, so I've had to do this:
boost::scoped_ptr<Object> a;
if (condition)
a = new Object(p1);
else
a = new Object(p2,p3,p4);
a->doSomething();
This feels too complex. Is there a better solutiuon?
Here's a very terrible hack, assuming Object is default-constructible:
Object a;
a.~Object();
if (condition) { ::new (&a) Object(p1); }
else { ::new (&a) Object(p2, p3, p4); }
Don't use this.
Another option is using a union, but you'll need to invoke the destructor manually in that setup as well.
A cleaner solution could be achieved with Boost.Optional (using in-place factories). (Thanks to #K-Ballo for digging up the details!)
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
struct Object
{
explicit Object(int) {}
explicit Object(int, float, std::string) {}
Object(Object const &) = delete;
Object(Object &&) = delete;
Object & operator=(Object const &) = delete;
Object & operator=(Object &&) = delete;
};
boost::optional<Object> a;
if (condition) { a = boost::in_place(0); }
else { a = boost::in_place(0, 1.0f, "two" ); }
Looks perfectly reasonable to me just the way it is. It's clear, simple and relatively concise.
auto const doSomethingTo = []( Object&& o ) { o.doSomething(); };
doSomethingTo( condition? Object( p1 ) : Object( p1, p2, p3 ) );
Disclaimer: code not touched by compiler.
EDIT: the code above, when the Object( Object&& ) constructor is private, fails to compile with MSVC 11.0 (yes even last year's November CTP), but does compile fine with MinGW g++ 4.7.1 and with some version of clang.
It appears that it should compile.
So, it's probably a bug in Visual C++ – but unfortunately I didn't find an easy workaround.
An uneasy workaround for the assumed-to-be Visual C++ compiler bug:
#include <fstream>
#include <iostream>
using namespace std;
class Object
{
private:
Object( Object const& );
Object( Object&& );
public:
void doSomething() const {}
Object( int ) {}
Object( int, int, int ) {}
};
int main( int argc, char* argv[] )
{
int p1 = 0, p2 = 0, p3 = 0;
bool condition = argc == 2;
auto const doSomething1 = [=]() { Object o( p1 ); o.doSomething(); };
auto const doSomething2 = [=]() { Object o( p1, p2, p3 ); o.doSomething(); };
if( condition ) { doSomething1(); } else { doSomething2(); }
}
Another answer maintains that new (read: a dynamic allocation) is your only option.
That's wrong.
There's really nothing wrong with your solution, although as
others have already mentionned, it would be more readably if you
used the conditional operator rather than if's. But you should
consider the possibility of refactoring. If you factor out all
of the code which uses the object into a separate function
(taking the object by reference), then something like:
if ( condition ) {
Object a( p1 );
doWhatever( a );
} else {
Object a( p2, p3, p4 );
doWhatever( a );
}
might be preferable (or not—I don't think that there's any
"right" answer with regards to choosing between these two).
I don't see the complexity... If you need to construct efficiently based on an if-condition declaring a pointer and using new is your only option. What you don't necessarily need to do is:
Use a scoped_ptr (altough that's usually a good idea)
Have the constructor in the if in your "main" code. Yours is a typical use case for a factory (see e.g. http://en.wikipedia.org/wiki/Factory_method_pattern).
EDIT: added "efficiently" in the second sentence.
I think your code is OK.
You just may want to consider the conditional operator ? :
boost::scoped_ptr<Object> a( condition ? new Object(p1) : new Object(p2,p3,p4) );
a->doSomething();
So, here is a quick trick to make this work, without manually constructing objects. Instead, I created a Deferred<T> template that represents an object in automatic storage whose construction is deferred (and possibly never occurs).
The buff in Deferred should be replaced with a union, because that will handle alignment issues (assuming you have C++11 features to support that). Asserts that constructed is true when you call get() is probably a good idea.
Once you have constructed your object, you can implicitly cast your Deferred<T> to a T&, then use that T& as an alias to the deferred-constructed T.
In theory, you could do away with the constructed bool if you could prove that it would always be constructed, but I'd advise against it. Other than that, this should be nearly as efficient as you can pull it off. And with the C++11 union case, it might even be standards compliant.
Oh yes, and it should be enhanced with perfect forwarding.
#include <utility>
// does not handle alignment issues:
template<typename T>
struct Deferred {
Deferred():constructed(false) {}
operator T&() { return get(); }
T& get() { return *reinterpret_cast<T*>(&buff[0]); }
template<typename... Args>
T& construct( Args... args ) {
new(&buff[0]) T(args...);
constructed = true;
return get();
}
~Deferred() {
if (constructed) {
get().~T();
}
}
private:
bool constructed;
char buff[sizeof(T)];
};
#include <iostream>
struct Object {
bool is_int;
Object( int x ):is_int(true) {}
Object( double d ):is_int(false) {}
~Object() {
std::cout << "~Object("<<is_int<<") destroyed\n";
}
};
enum which_test {
as_int,
as_double,
do_not,
};
void test(which_test v) {
std::cout << v << "\n";
Deferred<Object> o;
if(v==as_int) {
o.construct( 7 );
} else if (v==as_double) {
o.construct( 7.0 );
} else {
}
}
int main() {
test(as_int);
test(as_double);
test(do_not);
}

Chaining calls to temporaries in C++

I have a class that does a transformation on a string, like so
class transer{
transer * parent;
protected:
virtual string inner(const string & s) = 0;
public:
string trans(const string & s) {
if (parent)
return parent->trans(inner(s));
else
return inner(s);
}
transer(transer * p) : parent(p) {}
template <class T>
T create() { return T(this); }
template <class T, class A1> // no variadic templates for me
T create(A1 && a1) { return T(this, std::forward(a1)); }
};
So I can create a subclass
class add_count : public transer{
int count;
add_count& operator=(const add_count &);
protected:
virtual string inner(const string & s) {
return std::to_string((long long)count++) + s;
}
public:
add_count(transer * p = 0) : transer(p), count(0) {}
};
And then I can use the transformations:
void use_transformation(transer & t){
t.trans("string1");
t.trans("string2");
}
void use_transformation(transer && t){
use_trasnformation(t);
}
use_transformation(add_count().create<add_count>());
Is there a better design for this? I'd like to avoid using dynamic allocation/shared_ptr if I can, but I'm not sure if the temporaries will stay alive throughout the call. I also want to be able to have each transer be able to talk to its parent during destruction, so the temporaries also need to be destroyed in the right order. It's also difficult to create a chained transformation and save it for later, since
sometrans t = add_count().create<trans1>().create<trans2>().create<trans3>();
would save pointers to temporaries that no longer exist. Doing something like
trans1 t1;
trans2 t2(&t1);
trans3 t3(&t2);
would be safe, but annoying. Is there a better way to do these kinds of chained operations?
Temporaries will be destructed at the end of the full expression, in the
reverse order they were constructed. Be careful about the latter,
however, since there are no guarantees with regards to the order of
evaluation. (Except, of course, that of direct dependencies: if you
need one temporary in order to create the next—and if I've
understood correctly, that's your case—then you're safe.)
If you don't want dynamic allocation you either pass the data which is operated on to the function that initiates the chain, or you need a root type which holds it for you ( unless you want excessive copying ). Example ( might not compile ):
struct fooRef;
struct foo
{
fooRef create() { return fooRef( m_Val ); }
foo& operator=( const fooRef& a_Other );
std::string m_Val;
}
struct fooRef
{
fooRef( std::string& a_Val ) : m_Val( a_Val ) {}
fooRef create() { return fooRef( m_Val ); }
std::string& m_Val;
}
foo& foo::operator=( const fooRef& a_Other ) { m_Val = a_Other.m_Val; }
foo startChain()
{
return foo();
}
foo expr = startChain().create().create(); // etc
First the string lies on the temporary foo created from startChain(), all the chained operations operates on that source data. The assignment then at last copies the value over to the named var. You can probably almost guarantee RVO on startChain().

const-correctness and the safe bool idiom

I have another question related to the safe bool idiom:
typedef void (Testable::*bool_type)() const; // const necessary?
void this_type_does_not_support_comparisons() const {} // const necessary?
operator bool_type() const
{
return ok_ ? &Testable::this_type_does_not_support_comparisons : 0;
}
How come the bool_type (the typedef) and this_type_does_not_support_comparisons are const?
Nobody is supposed to actually call the member function through the return pointer anyway, right?
Is const necessary here? Would operator bool_type (the member function) violate const-correctness otherwise?
The "safe bool idiom" is the technical answer to the question "i want a vehicle that is both sports car and tractor, and maybe a boat". The practical answer is not the technical answer…
That said, the problem it solves is just to give a result that is convertible to bool but not to much of anything else (otherwise an instance of the class could be passed as actual argument where e.g. the formal argument was int, say). A data pointer could be convertible to void*. A function pointer isn't, at least formally within the C++ standard (Posix is something else, practice also).
Using a member function pointer protects against accidentally calling the function, given the pointer from the safe bool operator. The const constricts it a bit, but if fate has put someone on the path of making maximum number of silly mistakes, that person might still manage to call the do-nothing function. Instead of the const I think I would just let it have an argument of a private type, where other code cannot provide such an argument, and then it doesn't have to be a silly member function type anymore.
Can look like this:
#include <stdio.h>
class Foo
{
private:
enum PrivateArg {};
typedef void (*SafeBool)( PrivateArg );
static void safeTrue( PrivateArg ) {}
bool state_;
public:
Foo( bool state ): state_( state ) {}
operator SafeBool () const
{ return (state_? &safeTrue : 0); }
};
int main()
{
if( Foo( true ) ) { printf( "true\n" ); }
if( Foo( false ) ) { printf( "false\n" ); } // No output.
//int const x1 = Foo( false ); // No compilado!
//void* const x2 = Foo( false ); // No compilado!
}
Of course, the practical answer is instead something like this:
#include <stdio.h>
class Foo
{
private:
bool isEmpty_;
public:
Foo( bool asInitiallyEmpty )
: isEmpty_( asInitiallyEmpty )
{}
bool isEmpty() const { return isEmpty_; }
};
int main()
{
if( Foo( true ).isEmpty() ) { printf( "true\n" ); }
if( Foo( false ).isEmpty() ) { printf( "false\n" ); } // No output.
//bool const x0 = Foo( false ); // No compilado!
//int const x1 = Foo( false ); // No compilado!
//void* const x2 = Foo( false ); // No compilado!
}
Summary wrt. questions asked:
How come the bool_type (the typedef) and this_type_does_not_support_comparisons are const?
Somebody didn't quite understand what they coded. Or maybe they intended to restrict the ability to call, a little. But then, pretty futile measure.
Nobody is supposed to actually call the member function through the return pointer anyway, right?
Right.
Is const necessary here?
No.
Would operator bool_type (the member function) violate const-correctness otherwise?
No.
Cheers & hth.,
8.3.5/ A cv-qualifier-seq shall only be part of the function type for
a nonstatic member function, the function type to which a pointer to
member refers, or the top-level function type of a function typedef
declaration. The effect of a cv-qualifier-seq in a function declarator
is not the same as adding cv-qualification on top of the function
type, i.e., it does not create a cv-qualified function type.
If I read correctly, you can return a pointer to non const member in a const member function. You just won't be able to call it with a non const object.
A way to forbid the calling is:
private:
struct private_
{
void this_type_does_not_support_comparisons() {}
};
public:
typedef void (private_::*bool_type)() const;
operator bool_type() const
{
return ok_ ? &private_::this_type_does_not_support_comparisons : 0;
}
Pointer to member functions can still be compared for equality. You have to write an operator== and operator!= for Testable::bool_type types which trigger an error. Easier to do with the CRTP form of the safe bool idiom since those operators become templates and thus can have an erroneous body.
Example:
template <typename T>
class safe_bool_concept
{
// Implementation detail of safe bool
protected:
~safe_bool_concept() {}
public:
operator safe_bool() const
{
return static_cast<const T*>(this)->is_null() ? ...;
}
};
struct Foo : safe_bool_concept<Foo>
{
...
private:
friend class safe_bool_concept<Foo>;
bool is_null() const { ... }
};
then you can do (do the same with !=):
template <typename T>
void operator==(const safe_bool_concept<T>& x, const safe_bool_concept<T>&)
{
x.some_private_member(); // invalid, but won't be generated
// unless safe_bool classes are compared
}
This means that the safe bool idiom should be implemented via CRTP if you want to forbid comparisons. Comparisons to zero will still work however.
If you go the non-member function route, you'll have to provide <, >, <= and >= too.

C++ Virtual Constructor, without clone()

I want to perform "deep copies" of an STL container of pointers to polymorphic classes.
I know about the Prototype design pattern, implemented by means of the Virtual Ctor Idiom, as explained in the C++ FAQ Lite, Item 20.8.
It is simple and straightforward:
struct ABC // Abstract Base Class
{
virtual ~ABC() {}
virtual ABC * clone() = 0;
};
struct D1 : public ABC
{
virtual D1 * clone() { return new D1( *this ); } // Covariant Return Type
};
A deep copy is then:
for( i = 0; i < oldVector.size(); ++i )
newVector.push_back( oldVector[i]->clone() );
Drawbacks
As Andrei Alexandrescu states it:
The clone() implementation must follow the same pattern in all derived classes; in spite of its repetitive structure, there is no reasonable way to automate defining the clone() member function (beyond macros, that is).
Moreover, clients of ABC can possibly do something bad. (I mean, nothing prevents clients to do something bad, so, it will happen.)
Better design?
My question is: is there another way to make an abstract base class clonable without requiring derived classes to write clone-related code? (Helper class? Templates?)
Following is my context. Hopefully, it will help understanding my question.
I am designing a class hierarchy to perform operations on a class Image:
struct ImgOp
{
virtual ~ImgOp() {}
bool run( Image & ) = 0;
};
Image operations are user-defined: clients of the class hierarchy will implement their own classes derived from ImgOp:
struct CheckImageSize : public ImgOp
{
std::size_t w, h;
bool run( Image &i ) { return w==i.width() && h==i.height(); }
};
struct CheckImageResolution { ... };
struct RotateImage { ... };
...
Multiple operations can be performed sequentially on an image:
bool do_operations( vector< ImgOp* > v, Image &i )
{
for_each( v.begin(), v.end(),
/* bind2nd( mem_fun( &ImgOp::run ), i ... ) don't remember syntax */ );
}
If there are multiple images, the set can be split and shared over several threads. To ensure "thread-safety", each thread must have its own copy of all operation objects contained in v -- v becomes a prototype to be deep copied in each thread.
Edited: The thread-safe version uses the Prototype design pattern to enforce copy of pointed-to-objects -- not ptrs:
struct ImgOp
{
virtual ~ImgOp() {}
bool run( Image & ) = 0;
virtual ImgOp * clone() = 0; // virtual ctor
};
struct CheckImageSize : public ImgOp { /* no clone code */ };
struct CheckImageResolution : public ImgOp { /* no clone code */ };
struct RotateImage : public ImgOp { /* no clone code */ };
bool do_operations( vector< ImgOp* > v, Image &i )
{
// In another thread
vector< ImgOp* > v2;
transform( v.begin(), v.end(), // Copy pointed-to-
back_inserter( v2 ), mem_fun( &ImgOp::clone ) ); // objects
for_each( v.begin(), v.end(),
/* bind2nd( mem_fun( &ImgOp::run ), i ... ) don't remember syntax */ );
}
This has sense when image operation classes are small: do not serialize accesses to unique instances of ImgOps, rather provide each thread with their own copies.
The hard part is to avoid writers of new ImgOp-derived classes to write any clone-related code. (Because this is implementation detail -- this is why I dismissed Paul's answers with the Curiously Recurring Pattern.)
You can use the curiously recursive pattern but it might make your code less readable.
You will still need copy constructors. It works as follows.
struct ABC // Abstract Base Class
{
virtual ~ABC() {}
virtual ABC * clone() const = 0;
};
template <class TCopyableClass>
struct ClonableABC : public ABC
{
virtual ABC* clone() const {
return new TCopyableClass( *(TCopyableClass*)this );
}
};
struct SomeABCImpl : public ClonableABC<SomeABCImpl>
{};
A deep copy is then: [for loop]
You make the client clone the vector explicitly. I'm not sure if this answers your question, but I would suggest a vector of smart pointers so the cloning happens automatically.
std::vector<cloning_pointer<Base> > vec;
vec.push_back(cloning_pointer<Base>(new Derived()));
// objects are automatically cloned:
std::vector<cloning_pointer<Base> > vec2 = vec;
Of course, you don't want these implicit copies to happen when resizing a vector or something, so you need to be able to distinguish copies from moves. Here is my C++0x toy implementation of cloning_pointer which you might have to adjust to your needs.
#include <algorithm>
template<class T>
class cloning_pointer
{
T* p;
public:
explicit cloning_pointer(T* p)
{
this->p = p;
}
~cloning_pointer()
{
delete p;
}
cloning_pointer(const cloning_pointer& that)
{
p = that->clone();
}
cloning_pointer(cloning_pointer&& that)
{
p = that.p;
that.p = 0;
}
cloning_pointer& operator=(const cloning_pointer& that)
{
T* q = that->clone();
delete p;
p = q;
return *this;
}
cloning_pointer& operator=(cloning_pointer&& that)
{
std::swap(p, that.p);
return *this;
}
T* operator->() const
{
return p;
}
T& operator*() const
{
return *p;
}
};
Julien: && is not a "ref of ref", it is an rvalue reference which only binds to modifiable rvalues. See this excellent (but sadly slightly outdated) tutorial and video for an overview of rvalue references and how they work.
FYI, this is the design I came out with. Thank you Paul and FredOverflow for your inputs. (And Martin York for your comment.)
Step #1, Compile-time polymorphism with templates
Polymorphism is performed at compile-time using templates and implicit-interfaces:
template< typename T >
class ImgOp
{
T m_t; // Not a ptr: when ImgOp is copied, copy ctor and
// assignement operator perform a *real* copy of object
ImageOp ( const ImageOp &other ) : m_t( other .m_t ) {}
ImageOp & operator=( const ImageOp & );
public:
ImageOp ( const T &p_t ) : m_t( p_t ) {}
ImageOp<T> * clone() const { return new ImageOp<T>( *this ); }
bool run( Image &i ) const { return m_t.run( i); }
};
// Image operations need not to derive from a base class: they must provide
// a compatible interface
class CheckImageSize { bool run( Image &i ) const {...} };
class CheckImageResolution { bool run( Image &i ) const {...} };
class RotateImage { bool run( Image &i ) const {...} };
Now all the clone-related code lies within a unique class. However, it is now impossible to have a container of ImgOps templatized on different operations:
vector< ImgOp > v; // Compile error, ImgOp is not a type
vector< ImgOp< ImgOp1 > > v; // Only one type of operation :/
Step #2, Add a level of abstraction
Add a non-template base acting as an interface:
class AbstractImgOp
{
ImageOp<T> * clone() const = 0;
bool run( Image &i ) const = 0;
};
template< typename T >
class ImgOp : public AbstractImgOp
{
// No modification, especially on the clone() method thanks to
// the Covariant Return Type mechanism
};
Now we can write:
vector< AbstractImgOp* > v;
But it becomes hard to manipulate image operation objects:
AbstractImgOp *op1 = new AbstractImgOp;
op1->w = ...; // Compile error, AbstractImgOp does not have
op2->h = ...; // member named 'w' or 'h'
CheckImageSize *op1 = new CheckImageSize;
op1->w = ...; // Fine
op1->h = ...;
AbstractImgOp *op1Ptr = op1; // Compile error, CheckImageSize does not derive
// from AbstractImgOp? Confusing
CheckImageSize op1;
op1.w = ...; // Fine
op1.h = ...;
CheckImageResolution op2;
// ...
v.push_back( new ImgOp< CheckImageSize >( op1 ) ); // Confusing!
v.push_back( new ImgOp< CheckImageResolution >( op2 ) ); // Argh
Step #3, Add a "cloning pointer" class
Based on the FredOverflow's solution, make a cloning pointer to make the framework simpler to use.
However, this pointer needs not to be templatized for it is designed to hold only one type of ptr -- only the ctor needs to be templatized:
class ImgOpCloner
{
AbstractImgOp *ptr; // Ptr is mandatory to achieve polymorphic behavior
ImgOpCloner & operator=( const ImgOpCloner & );
public:
template< typename T >
ImgOpCloner( const T &t ) : ptr( new ImgOp< T >( t ) ) {}
ImgOpCloner( const AbstractImgOp &other ) : ptr( other.ptr->clone() ) {}
~ImgOpCloner() { delete ptr; }
AbstractImgOp * operator->() { return ptr; }
AbstractImgOp & operator*() { return *ptr; }
};
Now we can write:
CheckImageSize op1;
op1.w = ...; // Fine
op1.h = ...;
CheckImageResolution op2;
// ...
vector< ImgOpCloner > v;
v.push_back( ImgOpCloner( op1 ) ); // This looks like a smart-ptr, this is not
v.push_back( ImgOpCloner( op2 ) ); // confusing anymore -- and intent is clear