Often you have an object that would like to be shared in read-only form across the callers, but you would like someone to create copies when it's modified. Here is a small template that will do that for you automatically.
This is part of my multithreading library at github, here.
Code
template <typename T> class cow
{
private:
mutable std::shared_ptr<T> t;
public:
template< typename ...Args>
cow(Args ... args) { t = std::make_shared<T>(args...); }
cow(std::shared_ptr<T> t2)
{
t = t2;
}
operator const std::shared_ptr<T>() const { return t; }
const T operator *()
{
return *t;
}
shared_ptr<T> operator ->()
{
if (t.use_count() == 1)
return t;
std::shared_ptr<T> t2 = std::make_shared<T>(*t);
t = t2;
return t;
}
void write(std::function<void(std::shared_ptr<T> )> f)
{
f(operator ->());
}
};
You have the object to be manipulated in a shared_ptr<> form. The class constructor's take either an existing pointer or they can construct a new object with the aid of variadic template functions.
When using this class to read data, nothing happens:
struct FOO
{
int a1 = 0;
int a2 = 0;
};
std::shared_ptr<FOO> x = std::make_shared<FOO>();
cow<FOO> c1(x);
const FOO& j1 = *c1;
cow<FOO> c2 = c1;
All the above is serviced through the const operator/const T* cast functions.
When writing the data, the class duplicates the pointer before writing to it:
c1->a2 = 2;
Now c1 does not anymore contain the same as the original x, which remains untouched.
c1->a4 = 2;
There should be another copy but the previous one dissappears because it had a ref of 1, so it's all optimized out.
c2.write([](std::shared_ptr<FOO> t)
{
t->a1 = 10;
t->a2 = 20;
});
This would allow you to write once without creating uneccesary copies.
Have fun using it!
History
9 - 2 - 2020: First release