thorsten.schilling@gmail.com wrote:
> the question is, what is the "golden way" or the best way, if I have a
> memberfunction in a class, which should return a new instance of an
> object.
> For example some class Foo which holds a lot data and has the
> overloaded '+' operator and I want to do something like:
>
> //f1-f3 are all Foo instances
> f1 = f2+f3;
>
> Is it in that case better to work with pointers in general like:
>
> Foo* Foo::operator+(Foo& f){
> //Do stuff
> return new Foo([lot,of,data]);
> }
>
> to avoid the copying of the data which is hold by the new object at
> the end of the function? Or is there any sensefull way to implement
> that with a reference (Foo& Foo::operator+(Foo& f)), since it is more
> intuitive?
> Just imagine that the class Foo is somekind of Matrixclass with a big
> 2 dimensional array as member variable. Or is the only way just to
> write Foo that it holds only a pointer to that big variable? Sure,
> there are numerous solutions, but I would like to know which is the
> most common and most elegant by some experienced C++ developers.
You are concerned about the costs of copying a temporary object. There are
several things that help here:
a) A compiler can implement return value optimization. In the case of a
function like
Foo operator+ ( Foo const & lhs, Foo const & rhs ) {
Foo result ( something );
...
return ( result );
}
the standard permits that the result value be constructed in a place
convenient for the caller of operator+ so that copying the result is
avoided. Many compilers implement this. In this case, your question
interpreted in the narrowest scope becomes pointless. But a more general
concern about the copy costs of big objects remains.
b) The class can internally employ reference counting and make copying
cheap. I.e., you can implement Foo like so (untested, will be buggy):
class Foo {
tr1::shared_ptr< FooData > the_data;
void ensure_unique ( void ) {
if ( ! the_data.unique() ) {
shared_ptr< FooData > new_data ( new FooData ( *the_data ) );
the_data.swap( new_data );
}
}
public:
...
void some_const_method ( some_type some_par ) const {
the_data->some_const_method( some_par );
}
void some_non_const_method ( some_type some_par ) {
ensure_unique();
the_data->some_non_const_method( some_par );
}
};
Now, copying is cheap, but you add a little overhead just about everywhere
else. Also note that non-const members may have to create their private
copy of the data anyhow.
c) Expression templates can be used to trade the creation of costly
temporaries for creation of cheap temporaries. This technique is employed
in some publicly available matrix classes. Expression templates allow you
to reduce the number of costly objects created by postponing the actual
creation of costly objects to the very last moment (at which point some
temporaries have been bypassed). You will find plenty of information about
this in the archives.
BTW: if your Foo really is a matrix class, I strongly suggest using one of
the classes around. It is rather tricky to get a matrix class Right(tm).
Best
Kai-Uwe Bux