Very often, when I program, I use polymorphism because it naturally models the objects that I need. On the other hand I very often use standard containers to store these obj
How about writing a wrapper around foo
that incapsulates foo*
and implicitly converts to foo&
?
It uses a copy semantic that calls the underlying clone on the stored object to make a deep copy. This is at least not worse than the original intent to store everything by value. If you end up storing everything as a pointer to abstract base anyway then this has the same level of indirection as a unique_ptr
but is copyable (whereas unique_ptr
is not). On the other hand this is less overhead than shared_ptr
.
Add clone()
to the abstract hierarchy:
struct foo {
virtual void print() const = 0;
virtual ~foo() {};
virtual foo* clone() = 0;
};
struct goo : public foo {
int a;
void print() const { std::cout << "goo" << std::endl; }
foo* clone() { return new goo(*this); }
};
struct moo : public foo {
int a,b;
void print() const { std::cout << "moo" << std::endl; }
foo* clone() { return new moo(*this); }
};
Define foo_w
wrapper around foo
, see copy-and-swap idiom.
struct foo_w {
foo_w(foo *f = nullptr) : fp(f) {}
~foo_w() { delete fp; }
foo_w(const foo_w& that) : fp(that.fp->clone()) {}
foo_w(foo_w&& that) : foo_w() { swap(*this, that); }
foo_w& operator=(foo_w rhs) {
swap(*this, rhs);
return *this;
}
friend void swap(foo_w& f, foo_w& s) {
using std::swap;
swap(f.fp, s.fp);
}
operator foo&() { return *fp; }
operator const foo&() const { return *fp; }
foo& get() { return *fp; }
const foo& get() const { return *fp; }
// if we rewrite interface functions here
// calls to get() could be eliminated (see below)
// void print() { fp->print(); };
private:
foo *fp;
};
The usage is as follows:
#include <iostream>
#include <memory>
#include <vector>
// class definitions here...
int main() {
std::vector<foo_w> foos;
foos.emplace_back(new moo);
foos.emplace_back(new goo);
foos.emplace_back(new goo);
foos.emplace_back(new moo);
// variant 1: do it through a getter:
for(auto it = foos.begin(); it!=foos.end(); ++it) {
it->get().print();
// the presence of a proxy is almost hidden
// if we redefine interface in foo_w
// it->print();
}
// variant 2: use it through reference to foo
for(auto it = foos.begin(); it!=foos.end(); ++it) {
foo& fr = *it;
fr.print();
}
// variant 3: looks really nice with range-for
for(foo& fr : foos)
fr.print();
return 0;
}
The wrapper behavior is really up to what suits your needs. Probably if you're OK with unique_ptr
being not copyable that one is a better way to go, for me it was critical so I ended up with this. Also have a look at std::reference_wrapper
to store reference-like objects in the container.
You can use raw pointers and handle memory correctly
std::vector< AbstractBase*>
or you can use smart pointers, i.e std::shared_ptr
(a smart pointer that retains shared ownership of an object through a pointer) or std::unique_ptr
(smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr
goes out of scope) and let the library do memory management for you. So you end up then with something like
std::vector< std::shared_ptr<AbstractBase>>
or
std::vector< std::unique_ptr<AbstractBase>>
http://en.cppreference.com/w/cpp/memory/shared_ptr http://en.cppreference.com/w/cpp/memory/unique_ptr
One solution if you compiler supports C++11 features, would be to use std::vector<std::shared_ptr<foo>>
or std::vector<std::unique_ptr<foo>>
instead of raw pointers like the example below:
#include <iostream>
#include <memory>
#include <vector>
struct foo {
virtual void print() = 0;
};
struct goo : public foo {
int a;
void print() { std::cout << "goo"; }
};
struct moo : public foo {
int a,b;
void print() { std::cout << "moo"; }
};
auto main() -> int {
std::vector<std::shared_ptr<foo>> v{std::make_shared<goo>(), std::make_shared<moo>()};
for(auto i : v) {
i->print();
std::cout << std::endl;
}
return 0;
}
or with std::vector<std::unique_ptr<foo>>
:
auto main() -> int {
std::vector<std::unique_ptr<foo>> v;
v.push_back(std::move(std::unique_ptr<goo>(new goo)));
v.push_back(std::move(std::unique_ptr<moo>(new moo)));
for(auto it(v.begin()), ite(v.end()); it != ite; ++it) {
(*it)->print();
std::cout << std::endl;
}
return 0;
}
Thus, you wouldn't have to worry about memory deallocation.
I would recommend the use of a shared_ptr ie:
vector<shared_ptr<foo> >
instead of the raw pointer. That will take care of the vast majority of your memory management problems.
The second issue will still remain as you would need to redesign your interface in some areas. But there is nothing you can do about that as you need pointers when working with abstract base classes. You can't just access foo as a direct reference if foo is abstract. If you can, design your interface such that it hides these details.
Sorry this is probably not the answer you are looking for but this is my best recommendation.
You might wrap the polymorphic relationship of your classes and use a smart pointer:
#include <iostream>
#include <memory>
#include <vector>
class Base
{
protected:
struct Implementation
{
virtual ~Implementation() {}
virtual void print() const = 0;
};
Implementation& self() const { return *m_self; }
protected:
Base(std::shared_ptr<Implementation> self)
: m_self(self)
{}
public:
void print() const { self().print(); }
private:
std::shared_ptr<Implementation> m_self;
};
class Foo : public Base
{
protected:
struct Implementation : Base::Implementation
{
virtual void print() const { std::cout << "Foo\n"; }
};
Implementation& self() const { return static_cast<Implementation&>(Base::self()); }
public:
Foo() : Base(std::make_shared<Implementation>()) {}
};
class Goo : public Base
{
protected:
struct Implementation : Base::Implementation
{
virtual void print() const { std::cout << "Goo\n"; }
};
Implementation& self() const { return static_cast<Implementation&>(Base::self()); }
public:
Goo() : Base(std::make_shared<Implementation>()) {}
};
int main() {
std::vector<Base> v = { Foo(), Goo() };
for(const auto& x: v)
x.print();
}