Erik Wikstr?m wrote:
On 2007-04-24 10:49, Jeroen wrote:
Hi all,
I'm trying to implement a certain class but I have problems regarding
the copy ctor. I'll try to explain this as good as possible and show
what I tried thusfar. Because it's not about a certain code syntax
but more a 'code architecture' thing , I'll use simple example
classes (which are certainly not complete or working...) just to
illustrate the idea (and I may make some mistakes because I'm not
that experienced...).
The basic idea is that I have a class which has a data vector, but
objects of that class can also share that data vector between several
instances:
class A {
vector<double> *data; // pointer, so objects of 'A' can _share_ data.
bool data_is_shared; // does this 'A' share data with another A?
A(const bool do_data_init=true); // ctor
A(const A& a); // copy constructor
A get_shared_A(); // get an object A which shares 'this' data
};
Ctor:
A::A(bool do_data_init)
{
if (do_data_init)
data = new vector<double>;
data_is_shared = !do_data_init;
}
Copy ctor, always result in an 'A' which does not share data:
A::A(const A& a)
{
data = new vector<double>;
data_is_shared = false;
*data = *a.data;
}
Get an object A which shares data with 'this':
A A::get_shared_A()
{
A a(false);
a.data = data; // copy the data pointer only
return a;
}
The problems focus on this last method 'get_shared_A'. It should
return an object A that shares its data with 'this'. Problem: on
returning 'a', the copy constructor _may_ be called and then an
object A is returned which has its own data vector. So this doesn't
work... I cannot change the copy ctor because that should always
return an A which does not share its data (that's a requirement for
correct behaviour of class A).
In my application, 'get_shared_A' is an operator which selects a part
of the original data in 'this', and the returned result must be an
object A because it must be used in mathematical expressions just
like all other A's.
So, using a 'helper'-class B I tried to change this in:
A A::get_shared_A()
{
B b;
b.data = data; // copy the data pointer only
return b;
}
With class B:
class B {
vector<double> *data;
};
And an extra conversion ctor for A:
A::A(const& B b)
{
data = b.data;
data_is_shared = true;
}
So I wanted the code to force to use this new ctor and return an
object A which shares its data. But again, after the conversion ctor
is called it is still possible that the copy ctor is also called and
things do not work correctly.
In fact, all possible solutions I came up with do not work because
you cannot be sure if the copy ctor is called when returning from
'get_shared_A', it depends on the compiler you have.
So, does anybody has any ideas to overcome this problem?
Some time a go (Qt3) I took a look at the implicit sharing mechanism
of QList, the idea is that if you do something like this:
QList a;
/* add elements to a */
QList b = a;
then b will share the elements with a until one of them makes any
changes to the list, at which point it will "detach" (which basically
means that it will create a copy of the list and make the changes to
the copy).
If I understood your problem correctly it's quite similar but the
other way around, you want explicit sharing, but the idea should still
be the same and if you understand how they did it in Qt you should be
able to make it work for you (unless you need it to be thread-safe, at
which point it becomes a bit more tricky).
OK, thanks for the pointer :-) The problem that I came up with is a
little more 'sophisticated' than just sharing data. I try to implement a
matrix class which supports subscripting with a string, thus enabling to
'select' submatrices. For example:
matrix m(10,10); // 10x10 matrix
m("1:3,:") = 1; // rows 1 to 3 become '1'.
In this example, I use operator () for smart subscripting and this
operator must return a matrix object which only points to the selected
data range of its 'parent' matrix 'm' so it can be modified. Looks like
sharing data, but in this case I want the 'shared data' to be changed!
On the other hand, if you have a function (useless code by the way, but
just to illustrate things):
void my_function(matrix m)
{
m = 1;
}
and you call that by:
my_function(m("1:4,:"));
then my subscripting operator returns a matrix object which only points
to the selected data (this behaviour follows from the previous example),
but the copy constructor called when calling my_function must return a
matrix object which has its own data in order to prevent that the
original data is changed within my_function. But the copy ctor may
interfere within my operator () as I illustrated in my original post.
I'm at the point where I need to figure out all the functionality
required by correct matrix behaviour (the only thing I can come up with
is to generate as many possible situations like the previous examples),
and check if there isn't some inherent impossibility to make things
work.... Maybe this project is just too difficult for me :-)
a look at, if nothing else as an inspiration.