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
Related
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" );
}
I have code that makes use of some dirty tricks to make it appear as what I believe is a nice interface. The most important class, Worker, is designed to make the caller construct it with temporaries; the constructor will then take them. I think the code is self-explanatory:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
struct Base
{
virtual void
print
( void )
{
cout << "Base" << endl;
};
};
struct Derived1 : public Base
{
virtual void
print
( void )
{
cout << "Derived1" << endl;
};
};
struct Derived2 : public Base
{
virtual void
print
( void )
{
cout << "Derived2" << endl;
};
};
class Worker
{
private:
/* Arrays can't hold references, and
* vectors are homogenous, so the
* only option is to use (smart) pointers. */
vector< unique_ptr<Base> >
V
;
/* The dirty trick I spoke about. */
template<typename T> void
init
( T && t )
{
V.emplace_back( new T( forward<T>(t) ) );
return;
};
template<typename T , typename ... U> void
init
( T && t , U && ... u )
{
V.emplace_back( new T( forward<T>(t) ) );
/* The usage of std::move() is explained below. */
init(move(u)...);
return;
};
public:
template<typename ... T>
Worker
( T && ... t )
{
/* Use std::move() because, inside the body
* of the function, the arguments are lvalues.
* If I hadn't put std::move(), the compiler
* would complain about an attempt of using
* _new_ with a reference type (above). */
init(move(t)...);
return;
};
void
work
( void )
{
for ( const auto & x : V )
x->print();
return;
};
};
int
main
( void )
{
/* The goal: be able to create an instance of Worker
* passing temporaries to the constructor. No initializer_list
* is involved, no copies are made; clean, fast moves. */
Worker worker{ Derived1() , Base() , Derived2() };
/* This should print "Derived1\nBase\nDerived2\n". */
worker.work();
return 0;
}
Even though it compiles fine (g++ 4.8.1) and works out of the box, I feel this is not the best way to achieve my goals, and I'd like to get rid of that annoying feeling. Has anyone found another workaround for this? Are there any better aproaches, any disadvantages with my design?
Thanks in advance. The code should compile just fine, and show how I'd like my interface to be designed and why I've made use of those "tricks". Best regards,
Kalrish
Though I still think this question better belongs to Code Review, here's an alternative version for your "dirty trick"
template < typename T >
int emplace_back(T&& t)
{
V.emplace_back( std::forward<T>(t) );
return 0;
}
template<typename ... T>
Worker
( T && ... t )
{
auto i = {emplace_back(new T{forward<T>(t)})...};
};
Or, if you want to get rid of that member function:
public:
template<typename ... T>
Worker
( T && ... t )
{
using up = std::unique_ptr<Base>;
auto f = [&](up&& p)
{ V.emplace_back(std::move(p)); return 0; };
auto i = {f( up{new T{forward<T>(t)}} )...};
};
You might get a warning because i is unused, though. This variable is only required to build an initializer-list, where a pack-expansion is allowed.
Normally, I'd suggest using an initializer-list instead of the variadic template ctor (that's what they're made for), but they don't support moving out the elements as they don't own their storage.
The same problem occurs if you want to initialize the vector in the mem-initializer-list of the ctor (via pack expansion like in the alternative above).
I'm writing an interpreter in C++ for a lisp-like language of my humble design. This is for fun and for learning, so I'm not after absolute efficiency. But I am trying to have a very clean C++ code. I'm currently wondering how to implement builtin functions.
Basically, what I do is this :
I have an abstract base class DataObject which just provides type information (currently double, int, bool) and is inherited by the specific data containers, like :
class DataObject
{
public:
virtual const Type *type() = 0;
};
template<class T, const Type * myType>
class DataObjectValue : public DataObject
{
T value;
public:
const Type *type(){return myType;}
};
But then, when I want to perform say an addition I have to do things like :
DataObject * sum(DataObject *a, DataObject *b)
{
if(a->type() == &Integer and b->type == &Integer)
{
DataObjectValue<int>* ia = dynamic_cast< DataObjectValue<int>* >(a);
DataObjectValue<int>* ib = dynamic_cast< DataObjectValue<int>* >(b);
return new DataObjectValue<int>(ia->value+ib->value);
}
else if(a->type() == &Real and b->type == &Real)
{
DataObjectValue<double>* ra = dynamic_cast< DataObjectValue<double>* >(a);
DataObjectValue<double>* rb = dynamic_cast< DataObjectValue<double>* >(b);
return new DataObjectValue<double>(ra->value+rb->value);
}
else...
}
Which gets pretty annoying pretty quickly (do that for - * / < <= >= < > ....) and for several other types. This is hard to maintain. Of course I have simplified as much of the process as I could think of by introducing lots of templates everywhere, but still, I can't help but to think there must be a cleaner way. Do you a) see what my problem is (I doubt my explaining, not your competence) b) have any suggestion?
The current implementation that you have basically performs type erasure in the exact type that is being stored, and you are doing it in a slightly unusual way (why don't you use an enum rather than pointers to unique objects?)
I would start by providing promotion operations to the base class, and have them implemented in each level:
enum DataType {
type_bool,
type_int,
type_double
};
struct DataObject {
virtual ~DataObject() {} // remember to provide a virtual destructor if you
// intend on deleting through base pointers!!!
virtual DataType type() const = 0;
virtual bool asBool() const = 0;
virtual int asInt() const = 0;
virtual double asDouble() const = 0;
};
Then you can implement the operations in a simple functor:
template <typename T>
T sum_impl( T lhs, T rhs ) {
return lhs + rhs;
}
And provide a simple dispatch function:
DataType promoteTypes( DataType lhs, DataType rhs ) {
if ( lhs == type_double || rhs == type_double ) {
return type_double;
} else if ( lhs == type_int || rhs == type_int ) {
return type_int;
} else {
return type_bool;
}
}
template <template <typename T> T operation (T,T)>
DataObject* perform_operation( DataObject* lhs, DataObject* rhs, operation op ) const {
DataType result_type = promoteTypes( lhs->type(), rhs->type() );
switch ( result_type ) {
case type_double:
return new DataObjectValue<double>( op( lhs->asDouble(), rhs->asDouble() );
case type_int:
return new DataObjectValue<int>( op( lhs->asInt(), rhs->asInt() );
case type_bool:
return new DataObjectValue<bool>( op( lhs->asBool(), rhs->asBool() );
default:
abort();
}
}
With all the pieces in place, you can implement the operations almost trivially, by just providing a function template for the specific operation (as the sum above), and then using the rest of the places:
// sum_impl as above
DataObject* sum( DataObject* lhs, DataObject* rhs ) {
return perform_operation( lhs, rhs, sum_impl );
}
Now that is just the pattern I would use, but I would make some changes, I prefer to use as few pointers as possible, which means that I would not pass the arguments by pointer but rather by reference. Also, I would do proper type erasure (take a look at boost any) and make Object a complete type that contains DataObject elements, and then perform the operations on that type (rather than the hierarchy). That will enable you to provide functions that also return by value (and hide the dynamic memory allocations internally, which also means that resource management can be controlled inside Object and is not the responsibility of user code). With those changes, you can reuse and simplify the structure above and provide a cleaner solution.
If the two operands have to be the same type, then you can try this:
class DataObject
{
public:
virtual const Type *type() = 0;
virtual DataObject *operator+(DataObject&) = 0;
virtual DataObject *operator-(DataObject&) = 0;
virtual DataObject *operator*(DataObject&) = 0;
virtual DataObject *operator/(DataObject&) = 0;
};
template<class T, const Type * myType>
class DataObjectValue : public DataObject
{
typedef DataObjectValue<T, myType> selfType;
T value;
public:
const Type *type(){return myType;}
DataObject *operator+(DataObject& other) {
if (other.type() != myType)
return null;
selfType &otherValue = static_cast<selfType&>(other);
return new selfType(value + otherValue.value);
}
// etc.
};
Things get hairier when you start allowing int + double though. In some cases you can deal with that by checking all the types you know about (i.e. have already been declared), otherwise passing yourself to the other object:
if (other.type() != myType)
return other + *this; // assume *other is a <double> that knows how to add an <int>
You could use a macro aproach:
(I left the \ for brevity)
#define IMPLEMENT_OPERATOR(name, operator)
DataObject * name(DataObject *a, DataObject *b)
{
if(a->type() == &Integer and b->type == &Integer)
{
DataObjectValue<int>* ia = dynamic_cast< DataObjectValue<int>* >(a);
DataObjectValue<int>* ib = dynamic_cast< DataObjectValue<int>* >(b);
return new DataObjectValue<int>(ia->value operator ib->value);
}
else if(a->type() == &Real and b->type == &Real)
{
DataObjectValue<double>* ra = dynamic_cast< DataObjectValue<double>* >(a);
DataObjectValue<double>* rb = dynamic_cast< DataObjectValue<double>* >(b);
return new DataObjectValue<double>(ra->value operator rb->value);
}
else...
}
now, after this you can do this:
IMPLEMENT_OPERATOR(sum, +);
IMPLEMENT_OPERATOR(multiply, *);
IMPLEMENT_OPERATOR(division, /);
...
This would be fast and maintainable, but maybe problematic for special operators.
EDIT: Shahbaz mentioned that you can use Macros within other Macros. This can be applied in the following manner.
(again, \s left out for brevity)
#define IMPLEMENT_OPERATOR_TYPE(typeobject, internal_type, operator)
if(a->type() == &typeobject and b->type == &typeobject)
{
DataObjectValue<internal_type>* ia = dynamic_cast< DataObjectValue<internal_type>* >(a);
DataObjectValue<internal_type>* ib = dynamic_cast< DataObjectValue<internal_type>* >(b);
return new DataObjectValue<internal_type>(ia->value operator ib->value);
}
Which can now be used within the IMPLEMENT_OPERATOR macro:
#define IMPLEMENT_OPERATOR(name, operator)
DataObject * name(DataObject *a, DataObject *b)
{
IMPLEMENT_OPERATOR_TYPE(&Integer, int, operator);
IMPLEMENT_OPERATOR_TYPE(&Real, double, operator);
...
}
I'm new to smart pointers and I would be really grateful if somebody could give me a hint whether the way I'm handling smart pointers as class members is correct.
More precisely, the solution that I would like to achieve is in the context of class polymorphism and should be ideally exception-safe.
Given a container of heterogeneuous objects (std::vector<shared_ptr<CBase> > my_vector), the usual way to add elements is: my_vector.push_back( shared_ptr<CBase>(new CChild(1))), so that later on, one can call the member function of the specific derived class by doing: my_vector[0]->doSomething().
What I would like to achieve is to add stack objects to the vector and still being able to do polymorphism. Intuitively sth. like: CChild<float> obj1(1); my_vector.push_back(obj1). To solve that, I'm using now the Virtual Constructor Idiom: CChild obj1(1); my_vector.push_back(obj1.clone());.
Note that in some of my derived classes, I've static member functions that create objects, e.g: CChild<float> obj1 = CChild<float>::initType2(1);
Because of requirement issues and also to have a clean interface, I've now a new class CFoo<T> that has as data member a smart pointer to the CBase<T> class. The idea is that besides containing other new private members,
this class encapsulates/handles the smart pointers to the derived objects, such that I'm allowed to do sth. like: CFoo<float> myfoo(CChild<float>::initType2(1)); my_vector.push_back(myfoo);. This means that the container is now of type vector<CFoo<T> > instead of type vector<shared_ptr<CBase> >
It's in this context, that I would like to know how to implement the constructors for a class with smart pointers as class members? What about the implementation of the operator = following the copy-swap idiom? Below, I give some ilustrations of my class design:
template < typename T >
class CBase{
public:
CBase(){};
virtual ~CBase(){};
...
virtual CBase<T> * clone() const = 0;
virtual CBase<T> * create() const = 0;
};
template < typename T >
class CChild1 : public CBase{
public:
...
CChild1<T> * clone() const { return new CChild1<T>(*this); }
CChild1<T> * create() const { return new CChild1<T>(); }
static CChild1 initType1(double, double);
static CChild1 initType2(int);
};
template < typename T >
struct type{
typedef std::tr1::shared_ptr<T> shared_ptr;
};
template < typename T >
class CFoo{
public:
CFoo();
CFoo( const CBase<T> &, int = 0 );
CFoo( const CFoo<T> & );
void setBasePtr( const CBase<T> & );
void swap( CFoo<T> & );
CFoo<T> & operator = ( CFoo<T> );
...
~CFoo();
private:
typename type<CBase<T> >::shared_ptr m_ptrBase;
int m_nParam;
};
template < typename T >
CFoo<T>::CFoo()
:m_nParam(0)
// How shall I handle here the "m_ptrBase" class member? e.g point it to NULL?
{
}
template < typename T >
CFoo<T>::CFoo(const CBase<T> & refBase, int nParam)
:m_ptrBase(refBase.clone()), // Is this initialization exception-safe?
m_nParam(nParam)
{
}
template < typename T >
CFoo<T>::CFoo(const CFoo<T> & refFoo)
:m_ptrBase(refFoo.m_ptrBase),
m_nParam(refFoo.m_nParam)
{
}
template < typename T >
void CFoo<T>::setBasePtr( const CBase<T> & refBase ){
// ??? I would like to do sth. like: m_ptrBase(refBase.clone())
}
template < typename T >
CFoo<T>::~CFoo(){
// The memory is going to be freed by the smart pointer itself and therefore
// the destructor is empty, right?
}
template < typename T >
void CFoo<T>::swap( CFoo<T> & refFoo ){
//does this here makes sense?
using std::swap;
swap(m_ptrBase, refFoo.m_ptrBase);
swap(m_nParam, refFoo.m_nParam);
}
template < typename T >
CFoo<T> & CFoo<T>::operator = ( CFoo<T> copyFoo ){
copyFoo.swap(*this);
return (*this);
}
Below an example on what I would like to intuitively achieve. First, I fill the container with CFoo<float> objects that contain smart pointers to derived classes, besides another integer class member (Note that all this is only illustrative).
std::vector<CFoo<float> > my_bank;
for (int b=0; b < 3; b++){
float x = b*sqrt(2);
my_bank.push_back( new CFoo<float>( CChild1<float>::initType2(x), b) );
}
for (double s= 1.0; s<= 8.0; s *= 2.0){
my_bank.push_back( new CFoo<float>( CChild2<float>::initType2(x), 0) );
}
Once, the container is filled, I would like to do some operations, calling to virtual functions, e.g. doSomething that are specialized in each derived class.
for (int i=0; i < (int)my_bank.size(); i++){
int b = my_bank[i].m_nParam;
CBase<float>* myChild = my_bank[i].m_ptrBase;
myChild->doSomething( param1, param2, param3, ..., b);
}
I really don't know how to approach this. I don't understand half the interface requirements you've listed, so consider this an experimental answer that may not relate to your problem at all.
I suggest that you tell me what exactly is missing from my approach, and I can amend it. I'll omit templates for now, since they don't seem to be relevant to the problem.
So, without further ado, the simplest start uses a container of smart pointers:
#include <vector>
#include <memory>
struct Base
{
virtual void f();
};
typedef std::shared_ptr<Base> BasePtr;
typedef std::vector<BasePtr> BaseContainer;
struct DerivedA : Base
{
virtual void f();
// ...
};
// further derived classes
Usage:
int main()
{
BaseContainer v;
v.push_back(BasePtr(new DerivedB));
v.push_back(BasePtr(new DerivedC(true, 'a', Blue)));
BasePtr x(new DerivedA);
some_func(x);
x->foo()
v.push_back(x);
v.front()->foo();
}
If you happen to have some automatic object somewhere, you can insert a copy:
DerivedD d = get_some_d();
v.push_back(BasePtr(new DerivedD(d)));
To iterate:
for (BaseContainer::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
(*it)->foo();
}
Update: If you want to initialize an object after construction, you can do something like this:
{
DerivedE * p = new DerivedE(x, y, z);
p->init(a, b, c);
v.push_back(BasePtr(p));
}
Or, if the init function is virtual, even simpler:
v.push_back(BasePtr(new DerivedE(x, y, z)));
v.back()->init(a, b, c);
2nd Update: Here's how a derived object might look like:
struct DerivedCar : Base
{
enum EType { None = 0, Porsche, Dodge, Toyota };
DerivedCar(EType t, bool a, unsigned int p)
: Base(), type(t), automatic_transmission(a), price(p)
{
std::cout << "Congratulations, you know own a " << names[type] << "!\n"; }
}
private:
EType type;
bool automatic_transmission;
unsigned int price;
static const std::unordered_map<EType, std::string> names; // fill it in elsewhere
};
Usage: Base * b = new DerivedCar(DerivedCar::Porsche, true, 2000);
3rd Update: This one is unconnected, just an illustration of how to use lookup tables in favour of switch statements. Suppose we have lots of similar functions (same signature) that we want to use based on some integer:
struct Foo
{
void do_a();
void do_b();
// ...
void do(int n)
{
switch (n) {
case 2: do_a(); break;
case 7: do_b(); break;
}
}
};
Instead of the switch, we can register all functions in a lookup table. Here I'm assuming C++11 support:
struct Foo
{
// ...
static const std::map<int, void(Foo::*)()> do_fns;
void do(int n)
{
auto it = do_fns.find(n);
if (it != do_fns.end()) { (this->**it)(); }
}
};
const std::map<nt, void(Foo::*)()> Foo::do_fns {
{ 3, &Foo::do_a },
{ 7, &Foo::do_b },
// ...
};
Basically, you turn static code into container data. That's always a Good Thing. This is now easily scalable; you just add new functions to the lookup map as they come along. No need to touch the actual do() code again!
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().