How to make derived class do actions before calling base class? - c++

Before anything: I'm not a developer and I might not understand some of your messages, and as English is not my native language my question could be hard to understand.
Considering :
class MyVector
{
std::vector<command> vec;
std::mutex vector_m;
public:
void MVpush_back(command t)
{
this->vector_m.lock();
this->vec.push_back(t);
this->vector_m.unlock();
}
};
command is a custom class (its content doesn't seem relevant here; copy constructor does exist).
Basically, as I have a lot of possible writer & readers, thus I want to force the use of the mutex to access to the vec parameter.
As I'll only use push_back(), erase() and find() I could redefine them, but I was wondering if there is a way not have to redefine all functions.
something like:
<template> safe(*function name*<template>)
{
this->vector_m.lock();
<template> retval = vec.*function name*<parameter>;
this->vector_m.unlock();
return retval;
}
where the function to call is a kind of parameter...
I thought it could be done using std::initializer_list<type> but the type requirement is blocking.
Is there a way to do such a thing?
Rephrased question: is there a way to push a function with parameter(1) as parameter of a function(2) and make function(2) call function(1) ?

If you don't mind sacrificing the use of the member access operator (.), you can wrap all the vector operations neatly into lockable operations.
class MyVector {
std::vector<command> vec;
std::mutex vector_m;
struct locker {
MyVector& _ref;
locker(MyVector& parent) : _ref(parent) {
_ref.vector_m.lock();
}
~locker() { _ref.vector_m.unlock(); }
std::vector<command>* operator->() && { return &_ref.vec; }
};
public:
locker operator->() { return {*this}; }
};
Now, every access to the underlying vector will lock and unlock the vector for the duration of the operation:
MyVector mv;
mv->push_back(/* ... */);
// This locks the mutex before doing the push back
// And unlocks it immediately after, even in the face of exceptions.
The magic is in operator-> acting in a transitive manner. It is applied to the return value of itself until a regular pointer is returned, which is then accessed as usual. But every temporary along the way is created and destroyed in LIFO order. So the temporary MyVector::locker object has a lifetime that is just the duration of the access more or less.

Here's a quick not particularly fantastic version of the suggestion I made in the comments; not compiled or tested; just something so that you can get the idea.
template<class T>
class OverkillProtector {
private:
T& d;
std::unique_lock<std::mutex>lock ;
public:
OverkillProtector(T& d_, std::mutex& m_) :
d(d_),
lock(m_)
{}
OverkillProtector(const OverkillProtector&) = delete;
OverkillProtector& operator =(const OverkillProtector&) = delete;
T& getValue() { return d; }
const T& getValue() const { return d; }
};
Note that in the (default) desturctor, the unique lock will be destroyed, which will release the mutex. Note that the lifetime of this object is required to be less than that of the mutex or the data you're wrapping.

You might do something like:
class MyVector
{
std::vector<command> vec;
std::mutex vector_m;
public:
template <typename F>
decltype(auto) Do(F&& f)
{
std::unique_lock<std::mutex> lock{vector_m};
return std::forward<F>(f)(vec);
}
};
With usage similar to:
MyVector myVector;
command myCommand;
myVector.Do([&](auto& vec) { vec.push_back(myCommand); });

A template approach might look like this:
class MyVector
{
std::vector<command> vec;
mutable std::mutex vector_m;
public:
template <typename R, typename ... T, typename ... P>
R safeCall(R (std::vector<command>::*f)(T ...), P&& ... p)
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(std::forward<P>(p)...);
}
template <typename R, typename ... T, typename ... P>
R safeCall(R (std::vector<command>::*f)(T ...) const, P&& ... p) const
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(std::forward<P>(p)...);
}
};
void test()
{
MyVector v;
v.safeCall(&std::vector<int>::push_back, 7);
MyVector const* vv = &v;
int n = vv->safeCall(&std::vector<int>::operator[], 0);
}
Well, you safe the work of re-implementing the interface, but usage gets rather ugly – typedef for the vector type gets it minimally shorter, but still... A macro?
#define safe_call(V, R, F, ...) V R safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v, ., push_back, 7);
safe_call(vv, ->, operator[], 1);
Or a little shorter:
#define safe_call(V, F, ...) V safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v., push_back, 7);
safe_call(vv->, operator[], 1);
Well, I won't comment further, decide yourself...
In the end, you might bite the bullet and really duplicate the interface for the sake of more convenient usage afterwards - a helper template might facilitate the task, though:
class MyVector
{
std::vector<command> vec;
mutable std::mutex vector_m;
template <typename R, typename ... T>
R safeCall(R (std::vector<command>::*f)(T...), T... t)
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(t...);
}
// const variant, too
public:
// ...
};
void MyVector::push_back(Command t)
{
safeCall(&std::vector<Command>::push_back, t);
}

Related

How to implement a SingletonFactory?

I need some kind of class to manage the lifetime of singleton objects. I tried adding a method like this to my classes
static const FixedOutlineRect2D &instance() {
static const FixedOutlineRect2D self{};
return self;
}
Which has the nice property of constructing the object the first time it's called, but then it's not destroyed until the program is terminated which is messing up the order of deletions.
So I was thinking I could have some kind of "singleton factory" that would tie the lifetimes of all the objects to the factory and then I can destroy the whole thing as needed.
Here's what I've got so far:
class SingletonFactory {
public:
template<class T>
const T &get() {
if(!_map.template contains(typeid(T))) {
_map.template emplace(typeid(T), new T);
}
return *static_cast<const T*>(_map.at(typeid(T)));
}
~SingletonFactory() {
for(const auto& p : _map) {
delete p.second;
}
}
private:
std::unordered_map<std::type_index, const void*> _map{};
};
Usage would be like:
const Rect& rect = factory.get<FixedOutlineRect2D>();
Which would either coinstruct a new instance if one doesn't yet exist or return an existing instance.
But what I can't figure out is how to delete the instances. I'm getting an error:
Cannot delete expression with pointer-to-'void' type 'const void *'
Which makes sense because it can't know how many bytes to free unless it knows the type.
Can I get the type back out of the key so that I can cast and delete it? Or is there a better way to do what I'm trying?
This compiles and runs now:
class SingletonFactory {
public:
template<typename T, typename... Args>
const T &get(Args &&... args) {
// std::decay_t should be used
auto &cache = getCache<T, std::decay_t<Args>...>();
// Creating tuple from the arguments
auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
// Search for object in the cache
auto it = cache.find(arguments);
if (it != cache.end()) {
// Found. Return.
return *it->second;
}
// Not found. Add to cache.
auto *object = new T(std::forward<Args>(args)...);
cache.emplace(std::make_pair(std::move(arguments), object));
return *object;
}
private:
template<class T, class...Args>
static std::map<std::tuple<Args...>, const T *> &getCache() {
static std::map<std::tuple<Args...>, const T *> cache; // only run once
return cache;
}
};
(stolen and slightly modified from C++ templates std::tuple to void* and back)
But I still don't know how to clear out the caches... if I leave them as std::shared_ptr as OP had them it doesn't help exactly, they're still destructed at the end of the program. How can I iterate over all the static caches? If I had a map of caches/maps I could do it, but I don't think I can.
delete pointer to void will not call constructor ~T. You should store deleter of T. For example
std::unordered_map<std::type_index, std::pair<void*, void(*)(void*)>> _map;
_map.emplace(typeid(T), std::make_pair(new T, [](void* p){ delete static_cast<T*>(p); }));
for (const auto& p : _map) {
p.second.second(p.second.first);
}
I suggest making template SingletonFactory::get() a static member, and a static SingletonFactory::clean() instead of the destructor.
class SingletonFactory {
public:
template<class T>
static const T &get() {
if(!_map.count(typeid(T))) {
_map.emplace(typeid(T), std::make_pair(new T, [](const void* p){ delete (T*)(p); }));
}
return *static_cast<const T*>(_map.at(typeid(T)).first);
}
static void clean() {
for(const auto& p : _map) {
p.second.second(p.second.first);
}
}
private:
static std::unordered_map<std::type_index, std::pair<const void*, void(*)(const void*)>> _map;
};
std::unordered_map<std::type_index, std::pair<const void*, void(*)(const void*)>> SingletonFactory::_map;

How to simulate Rust's Mutex<Object> in C++?

Having an object and a mutex as 2 different variables is kinda error prone
MyObject myObject;
std::mutex myObjectMutex;
I tend to forget to lock it sometimes.
On Rust, a shared object is required to be inside a mutex:
std::sync::Mutex<MyObject> mySharedObject
So I have to use like this:
mySharedObject.lock().unwrap().objectMethod()
What would be the less error prone way to simulate something like this in C++ so I don't forget to lock it?
I thought of an std::tuple<std::mutex, MyObject> but it's not very good and I can forget to lock.
One way to do it is have your Mutex<T> only allow access to the contained T via a lambda:
template <typename T>
class Mutex {
private:
T value;
std::mutex mutex;
public:
// Fill out some constructors, probably some kind of emplacement constructor too.
// For simplicity of the example, this should be okay:
explicit Mutex(T value)
: value(std::move(value))
{}
template <typename F>
auto locked(F&& fn) const& -> std::invoke_result_t<F&&, T const&> {
// Lock the mutex while invoking the function.
// scoped_lock automatically unlocks at the end of the scope
std::scoped_lock lock(mutex);
return std::invoke(std::forward<F>(fn), value);
}
template <typename F>
auto locked(F&& fn) & -> std::invoke_result_t<F&&, T&> {
std::scoped_lock lock(mutex);
return std::invoke(std::forward<F>(fn), value);
}
// Can be worth repeating for const&& and && as well
};
Usage:
mySharedObject.locked([] (MyObject& obj) { return obj.objectMethod(); });
It's still possible to defeat this by stashing a reference to the obj inside a .locked(...) call and using the reference outside of .locked(...), but that would almost require deliberately trying to do the wrong thing.
Also, be aware that it being in a lambda can be quite limiting, as regular control flow no longer works (return doesn't return from the outer scope, continue/break don't work, etc.)
I think the following is very near regardless of the lifetime parameter
#include <atomic>
template<class T>
class MutexGuard{
T& inner;
std::atomic_flag & locked;
public:
MutexGuard(T& inner, std::atomic_flag& locked): inner{inner}, locked{locked}{}
operator T&()&{
return inner;
}
~MutexGuard(){
locked.clear();
}
};
template<class T>
class Mutex{
std::atomic_flag locked{false};
T inner;
public:
Mutex(T&& inner):inner{std::move(inner)}{}
Mutex(const T&) = delete;
MutexGuard<T> lock(){
while(locked.test_and_set());
return MutexGuard<T>{inner, locked};
}
};
Demo

Create library to override operator*() of iterator - risk dangling pointer

I am trying to create my own boost::adaptors::transformed.
Here is the related boost code.
Here is its usage (modified from a SO answer by LogicStuff):-
C funcPointer(B& b){
//"funcPointer" is function convert from "B" to "C"
return instance-of-C
}
MyArray<B> test; //<-- any type, must already have begin() & end()
for(C c : test | boost::adaptor::transformed(funcPointer)) {
//... something ....
}
The result will be the same as :-
for(auto b : test) {
C c = funcPointer(b);
//... something ...
}
My Attempt
I created CollectAdapter that aim to work like boost::adaptor::transformed.
It works OK in most common cases.
Here is the full demo and back up. (same as below code)
The problematic part is CollectAdapter - the core of my library.
I don't know whether I should cache the collection_ by-pointer or by-value.
CollectAdapter encapsulates underlying collection_ (e.g. pointer to std::vector<>) :-
template<class COLLECTION,class ADAPTER>class CollectAdapter{
using CollectAdapterT=CollectAdapter<COLLECTION,ADAPTER>;
COLLECTION* collection_; //<---- #1 problem? should cache by value?
ADAPTER adapter_; //<---- = func1 (or func2)
public: CollectAdapter(COLLECTION& collection,ADAPTER adapter){
collection_=&collection;
adapter_=adapter;
}
public: auto begin(){
return IteratorAdapter<
decltype(std::declval<COLLECTION>().begin()),
decltype(adapter_)>
(collection_->begin(),adapter_);
}
public: auto end(){ ..... }
};
IteratorAdapter (used above) encapsulates underlying iterator, change behavior of operator* :-
template<class ITERATORT,class ADAPTER>class IteratorAdapter : public ITERATORT {
ADAPTER adapter_;
public: IteratorAdapter(ITERATORT underlying,ADAPTER adapter) :
ITERATORT(underlying),
adapter_(adapter)
{ }
public: auto operator*(){
return adapter_(ITERATORT::operator*());
}
};
CollectAdapterWidget (used below) is just a helper class to construct CollectAdapter-instance.
It can be used like:-
int func1(int i){ return i+10; }
int main(){
std::vector<int> test; test.push_back(5);
for(auto b:CollectAdapterWidget::createAdapter(test,func1)){
//^ create "CollectAdapter<std::vector<int>,func1>" instance
//here, b=5+10=15
}
}
Problem
The above code works OK in most cases, except when COLLECTION is a temporary object.
More specifically, dangling pointer potentially occurs when I create adapter of adapter of adapter ....
int func1(int i){ return i+10; }
int func2(int i){ return i+100; }
template<class T> auto utilityAdapter(const T& t){
auto adapter1=CollectAdapterWidget::createAdapter(t,func1);
auto adapter12=CollectAdapterWidget::createAdapter(adapter1,func2);
//"adapter12.collection_" point to "adapter1"
return adapter12;
//end of scope, "adapter1" is deleted
//"adapter12.collection_" will be dangling pointer
}
int main(){
std::vector<int> test;
test.push_back(5);
for(auto b:utilityAdapter(test)){
std::cout<< b<<std::endl; //should 5+10+100 = 115
}
}
This will cause run time error. Here is the dangling-pointer demo.
In the real usage, if the interface is more awesome, e.g. use | operator, the bug will be even harder to be detected :-
//inside "utilityAdapter(t)"
return t|func1; //OK!
return t|func1|func2; //dangling pointer
Question
How to improve my library to fix this error while keeping performance & robustness & maintainablilty near the same level?
In other words, how to cache data or pointer of COLLECTION (that can be adapter or real data-structure) elegantly?
Alternatively, if it is easier to answer by coding from scratch (than modifying my code), go for it. :)
My workarounds
The current code caches by pointer.
The main idea of workarounds is to cache by value instead.
Workaround 1 (always "by value")
Let adapter cache the value of COLLECTION.
Here is the main change:-
COLLECTION collection_; //<------ #1
//changed from .... COLLECTION* collection_;
Disadvantage:-
Whole data-structure (e.g. std::vector) will be value-copied - waste resource.
(when use for std::vector directly)
Workaround 2 (two versions of library, best?)
I will create 2 versions of the library - AdapterValue and AdapterPointer.
I have to create related classes (Widget,AdapterIterator,etc.) as well.
AdapterValue - by value. (designed for utilityAdapter())
AdapterPointer - by pointer. (designed for std::vector)
Disadvantage:-
Duplicate code a lot = low maintainability
Users (coders) have to be very conscious about which one to pick = low robustness
Workaround 3 (detect type)
I may use template specialization that do this :-
If( COLLECTION is an "CollectAdapter" ){ by value }
Else{ by pointer }
Disadvantage:-
Not cooperate well between many adapter classes.
They have to recognize each other : recognized = should cache by value.
Sorry for very long post.
I personally would go with template specialisation – however, not specialise the original template, but a nested class instead:
template<typename Collection, typename Adapter>
class CollectAdapter
{
template<typename C>
class ObjectKeeper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C, typename A>
class ObjectKeeper <CollectAdapter<C, A>>
{
CollectAdapter<C, A> object;
public:
CollectAdapter<C, A>* operator*() { return &object; };
CollectAdapter<C, A>* operator->() { return &object; };
};
ObjectKeeper<Collection> keeper;
// now use *keeper or keeper-> wherever needed
};
The outer class then covers both cases by just always using pointers while the nested class hides the differences away.
Sure, incomplete (you yet need to add appropriate constructors, for instance, both to outer and inner class), but it should give you the idea...
You might even allow the user to select if she/he wants to copy:
template<typename Collection, typename Adapter, bool IsAlwaysCopy = false>
class CollectAdapter
{
template<typename C, bool IsCopy>
class ObjectWrapper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C>
class ObjectWrapper<C, true>
{
C object;
public:
C* operator*() { return &object; };
C* operator->() { return &object; };
};
// avoiding code duplication...
template<typename C, bool IsCopy>
class ObjectKeeper : public ObjectWrapper<C, IsCopy>
{ };
template<typename C, typename A, bool IsCopy>
class ObjectKeeper <CollectAdapter<C, A>, IsCopy>
: public ObjectWrapper<CollectAdapter<C, A>, true>
{ };
ObjectKeeper<Collection> keeper;
};
In my indexed_view I store the value of the collection if it is an rvalue, and store a reference if it is an lvalue. You could do the same here: overload your operator| for both rvalues and lvalues.
template<typename Collection,typename Filter>
auto operator|(Collection&& collection,Filter filter){
return create_adapter_for_rvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection const& collection,Filter filter){
return create_adapter_for_const_lvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection & collection,Filter filter){
return create_adapter_for_non_const_lvalue_collection(collection,filter);
}

Accessing template class structure type members

Ok, the question title is a bit hard to phrase. What I am trying to achieve is create a template class with get/set functions that can handle simple types and structures.
This is simple for types such as integers and char, etc... But when the template type 'T' is a struct then it gets harder.
For example, here is a template class, where I have omitted various parts of it (such as constructor, etc), but it shows the get/set function:
EDIT: Only this class is allowed to modify the data, so passing a reference outside is not allowed. The reason is that I want to do a mutex around the set/get. I will/have update the functions...
template <class T> class storage
{
private:
T m_var;
pthread_mutex_t m_mutex;
public:
void set(T value)
{
pthread_mutex_lock(&m_mutex);
m_var = value;
pthread_mutex_unlock(&m_mutex);
}
T get(void)
{
T tmp;
// Note: Can't return the value within the mutex otherwise we could get into a deadlock. So
// we have to first read the value into a temporary variable and then return that.
pthread_mutex_lock(&m_mutex);
tmp = m_var;
pthread_mutex_unlock(&m_mutex);
return tmp;
}
};
Then consider the following code:
struct shape_t
{
int numSides;
int x;
int y;
}
int main()
{
storage<int> intStore;
storage<shape_t> shapeStore;
// To set int value I can do:
intStore.set(2);
// To set shape_t value I can do:
shape_t tempShape;
tempShape.numSides = 2;
tempShape.x = 5;
tempShape.y = 4;
shapeStore.set(tempShape);
// To modify 'x' (and keep y and numSides the same) I have to do:
shape_t tempShape = shapeStore.get();
tempShape.x = 5;
shapeStore.set(tempShape);
}
What I want to be able to do, if its possible, is to set the members of shape_t individually via some means in the template class, something like:
shapeStore.set(T::numSides, 2);
shapeStore.set(T::x, 5);
shapeStore.set(T::y, 4);
And not have to use a temp var. Is this possible? how?
I looked at this answer, but it did not quite do what I wanted because it is for a specific structure type
Make your get() member return a reference:
T& get()
{
return m_var;
}
Then you could say
shapeStore.get().x = 42;
Note it is good practice to add a const overload:
const T& get() const
{
return m_var;
}
Also note that if your get and set methods really do nothing special, as in your example, you might consider making the data public and doing away with getters/setters:
template <class T> struct storage
{
T m_var;
};
Edit: If you want to allow synchronised changes to the member, an option is to have a method that takes a modifying function. The function is applied inside the class, in your case, protected by the mutex. For example,
template <class T> struct storage
{
storage() : m_var() {}
void do_stuff(std::function<void(T&)> f)
{
std::lock_guard<std::mutex> lock(m_mutex);
f(m_var);
}
private:
T m_var;
std::mutex_t m_mutex;
};
Then you can modify members in a synchronised manner:
storage<shape_t> shapeStore;
shapeStore.do_stuff([](shape_t& s)
{ s.x = 42;
s.y = 100; });
If you don't have C++11 you can pass a function instead:
void foo(shape_t& s) { s.x = 42; }
shapeStore.do_stuff(foo);
Your design is fairly workable for primitive types, but it requires you to replicate the entire interface of class types and quickly becomes unmanageable. Even in the case of primitive types, you might want to enable more complex atomic operations than simply get and set, e.g., increment or add or multiply. The key to simplifying the design is to realize that you don't actually want to interpose on every single operation the client code performs on the data object, you only need to interpose before and after the client code atomically performs a sequence of operations.
Anthony Williams wrote a great article in Doctor Dobb's Journal years ago about this exact problem using a design where the manager object provides a handle to the client code that the client uses to access the managed object. The manager interposes only on the handle creation and destruction allowing clients with a handle unfettered access to the managed object. (See the recent proposal for standardization for excruciating detail.)
You could apply the approach to your problem fairly easily. First, I'll replicate some parts of the C++11 threads library because they make it MUCH easier to write correct code in the presence of exceptions:
class mutex {
pthread_mutex_t m_mutex;
// Forbid copy/move
mutex(const mutex&); // C++11: = delete;
mutex& operator = (const mutex&); // C++11: = delete;
public:
mutex(pthread_mutex_) { pthread_mutex_init(&m_mutex, NULL); }
~mutex() { pthread_mutex_destroy(&m_mutex); }
void lock() { pthread_mutex_lock(&m_mutex); }
void unlock() { pthread_mutex_unlock(&m_mutex); }
bool try_lock() { return pthread_mutex_trylock(&m_mutex) == 0; }
};
class lock_guard {
mutex& mtx;
public:
lock_guard(mutex& mtx_) : mtx(mtx_) { mtx.lock(); }
~lock_guard() { mtx.unlock(); }
};
The class mutex wraps up a pthread_mutex_t concisely. It handles creation and destruction automatically, and saves our poor fingers some keystrokes. lock_guard is a handy RAII wrapper that automatically unlocks the mutex when it goes out of scope.
storage then becomes incredibly simple:
template <class> class handle;
template <class T> class storage
{
private:
T m_var;
mutex m_mutex;
public:
storage() : m_var() {}
storage(const T& var) : m_var(var) {}
friend class handle<T>;
};
It's simply a box with a T and a mutex inside. storage trusts the handle class to be friendly and allows it poke around its insides. It should be clear that storage does not directly provide any access to m_var, so the only way it could possibly be modified is via a handle.
handle is a bit more complex:
template <class T>
class handle {
T& m_data;
lock_guard m_lock;
public:
handle(storage<T>& s) : m_data(s.m_var), m_lock(s.m_mutex) {}
T& operator* () const {
return m_data;
}
T* operator -> () const {
return &m_data;
}
};
it keeps a reference to the data item and holds one of those handy automatic lock objects. The use of operator* and operator-> make handle objects behave like a pointer to T.
Since only way to access the object inside storage is through a handle, and a handle guarantees that the appropriate mutex is held during its lifetime, there's no way for client code to forget to lock the mutex, or to accidentally access the stored object without locking the mutex. It can't even forget to unlock the mutex, which is nice as well. Usage is simple (See it working live at Coliru):
storage<int> foo;
void example() {
{
handle<int> p(foo);
// We have exclusive access to the stored int.
*p = 42;
}
// other threads could access foo here.
{
handle<int> p(foo);
// We have exclusive access again.
*p *= 12;
// We can safely return with the mutex held,
// it will be unlocked for us in the handle destructor.
return ++*p;
}
}
You would code the program in the OP as:
struct shape_t
{
int numSides;
int x;
int y;
};
int main()
{
storage<int> intStore;
storage<shape_t> shapeStore;
// To set int value I can do:
*handle<int>(intStore) = 2;
{
// To set shape_t value I can do:
handle<shape_t> ptr(shapeStore);
ptr->numSides = 2;
ptr->x = 5;
ptr->y = 4;
}
// To modify 'x' (and keep y and numSides the same) I have to do:
handle<shape_t>(shapeStore)->x = 5;
}
I can propose you alternative solution.
When you need you can get special template class that allows managing containing object.
template < typename T >
class SafeContainer
{
public:
// Variadic template for constructor
template<typename ... ARGS>
SafeContainer(ARGS ...arguments)
: m_data(arguments ...)
{};
// RAII mutex
class Accessor
{
public:
// lock when created
Accessor(SafeContainer<T>* container)
:m_container(container)
{
m_container->m_mutex.lock();
}
// Unlock when destroyed
~Accessor()
{
m_container->m_mutex.unlock();
}
// Access methods
T* operator -> ()
{
return &m_container->m_data;
}
T& operator * ()
{
return m_container->data;
}
private:
SafeContainer<T> *m_container;
};
friend Accessor;
Accessor get()
{
return Accessor(this);
}
private:
T m_data;
// Should be using recursive mutex to avoid deadlocks
std::mutex m_mutex;
};
Example:
struct shape_t
{
int numSides;
int x;
int y;
};
int main()
{
SafeContainer<shape_t> shape;
auto shapeSafe = shape.get();
shapeSafe->numSides = 2;
shapeSafe->x = 2;
}

Template type deduction with a non-copyable class

Suppose I have an autolocker class which looks something like this:
template <T>
class autolocker {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
~autolocker() {
lock->unlock();
}
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
T *lock;
};
Obviously the goal is to be able to use this autolocker with anything that has a lock/unlock method without resorting to virtual functions.
Currently, it's simple enough to use like this:
autolocker<some_lock_t> lock(&my_lock); // my_lock is of type "some_lock_t"
but it is illegal to do:
autolocker lock(&my_lock); // this would be ideal
Is there anyway to get template type deduction to play nice with this (keep in my autolocker is non-copyable). Or is it just easiest to just specify the type?
Yes you can use the scope-guard technique
struct autolocker_base {
autolocker_base() { }
protected:
// ensure users can't copy-as it
autolocker_base(autolocker_base const&)
{ }
autolocker_base &operator=(autolocker_base const&)
{ return *this; }
};
template <T>
class autolocker : public autolocker_base {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
autolocker(const autolocker& o)
:autolocker_base(o), lock(o.lock)
{ o.lock = 0; }
~autolocker() {
if(lock)
lock->unlock();
}
private:
autolocker& operator=(const autolocker&);
private:
mutable T *lock;
};
Then write a function creating the autolocker
template<typename T>
autolocker<T> makelocker(T *l) {
return autolocker<T>(l);
}
typedef autolocker_base const& autolocker_t;
You can then write it like this:
autolocker_t lock = makelocker(&my_lock);
Once the const reference goes out of scope, the destructor is called. It doesn't need to be virtual. At least GCC optimizes this quite well.
Sadly, this means you have to make your locker-object copyable since you need to return it from the maker function. But the old object won't try to unlock twice, because its pointer is set to 0 when it's copied, so it's safe.
Obviously you can't get away with autolocker being a template, because you want to use it as a type, and templates must be instantiated in order to obtain types.
But type-erasure might be used to do what you want. You turn the class template into a class and its constructor into a member template. But then you'd have to dynamically allocate an inner implementation object.
Better, store a pointer to a function that performs the unlock and let that function be an instance of a template chosen by the templatized constructor. Something along these lines:
// Comeau compiles this, but I haven't tested it.
class autolocker {
public:
template< typename T >
autolocker(T *l) : lock_(l), unlock_(&unlock<T>) { l->lock(); }
~autolocker() { unlock_(lock_); }
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
typedef void (*unlocker_func_)(void*);
void *lock_;
unlocker_func_ unlock_;
template <typename T>
static void unlock(void* lock) { ((T*)lock)->unlock(); }
};
I haven't actually tried this and the syntax might be wrong (I'm not sure how to take the address of a specific function template instance), but I think this should be doable in principle. Maybe someone comes along and fixes what I got wrong.
I like this a lot more than the scope guard, which, for some reason, I never really liked at all.
I think jwismar is correct and what you want is not possible with C++. However, a similar (not direct analogue) construct is possible with C++0x, using several new features (rvalues/moving and auto variable type):
#include <iostream>
template <typename T>
class autolocker_impl
{
public:
autolocker_impl(T *l) : lock(l) {
lock->lock();
}
autolocker_impl (autolocker_impl&& that)
: lock (that.lock)
{
that.lock = 0;
}
~autolocker_impl() {
if (lock)
lock->unlock();
}
private:
autolocker_impl(const autolocker_impl&);
autolocker_impl& operator=(const autolocker_impl&);
private:
T *lock;
};
template <typename T>
autolocker_impl <T>
autolocker (T* lock)
{
return autolocker_impl <T> (lock);
}
struct lock_type
{
void lock ()
{ std::cout << "locked\n"; }
void unlock ()
{ std::cout << "unlocked\n"; }
};
int
main ()
{
lock_type l;
auto x = autolocker (&l);
}
autolocker is a class template, not a class. Your "this would be ideal" is showing something that doesn't make sense in C++.