I've been trying to solve a design problem involving both an abstract type and its derived classes, as well as std containers. I have a working solution, but I would like to see if it can be improved. I apologize for the "..."s. But it is to make the design issue more clear.
// the base class
class B {
private:
...
public:
// the virtual function which makes B an abstract type
virtual void func(...) = 0;
...
};
// the 1st derived class
class D1 : public B {
...
void func(...) {...}
};
// the 2nd derived class
class D2 : public B {
...
void func(...) {...}
};
Based on the problem, both D1
and D2
have to point to or contain some instances of B
w/o knowing their concrete types. Currently, I'm using the point to approach, which means D1
and D2
contain some pointers to B
.
In addition, those pointed-to instances of B
are in fact shared among higher-level instances of B
in recursive compositions. To make it clear, I'll expand the definition of D1
.
class D1 : public B {
private:
B *d1_b1;
B *d1_b2;
...
public:
D1 (B *b1, B *b2) {...}
B* func(...) {...}
...
};
Now, although d1_b1
and d1_b2
are shared by some higher-level instances of either D1
or D2
, I think none of higher-level objects should maintain the ownership or lifetime of lower-level objects. Instead, I use an std container with unique_ptr
s, for example:
std::vector<std::unique_ptr<B>> unique_b_objs;
The unique_b_objs
is declared at the scope where the recursive construction is first called, and is passed in by reference and used recursively.
Now, every time an new object of either D1
or D2
is created, a corresponding unique_ptr
is pushed back into unique_b_objs
. Essentially, the raw pointers to objects of B are used in recursive composition, but the lifetime and ownership of the objects of B are managed by the std container.
I hope I've made it clear so far. It's working as expected. But I'm trying to get rid of the raw pointers. I can think of two approaches, but none of them work right now.
- Use the "contain" approach. Essentially, all the
B *
becomesB
inD1
andD2
. ButB
is an abstract type, which means compilers won't even compile something likeD1 (B b1, B b2) {...}
- Use reference in the container. It can be done via the
reference_wrapper
. However, since the objects are created locally in recursions, the references become invalid out of the scope. This means we cannot transport references between recursive calls.
One working approach is to use shared_ptr
. But it is unnecessary to share the ownership at every recursion step. And it also leads to performance overhead.
At this point, thank you for reading through the question. I hope I've made it clear. If you can think of some better approach than a container of unique_ptr
s + raw pointers, please let me know.
Aucun commentaire:
Enregistrer un commentaire