#define
не предоставляют никакой защиты как таковой, скорее, они просто уменьшают количество набираемых вами символов (в свою очередь, они гарантируют, что все «защищенные» члены имеют правильный код вplace).
Я не знаю, как избежать необходимости помещать проверки в каждую функцию получения - и блокировать весь объект, так как они возвращают ссылки на данные, хранящиеся в защищенном объекте.,
Если, однако, все они могут быть возвращены по значению (или вообще ничего не возвращать), то вы можете использовать контейнер, который блокирует все, используя прокси-объект, что-то вроде следующего (это, вероятно, можно сделать лучше, я просто быстро взломал его вместе):
#include <iostream>
struct Mutex
{
void lock()
{
std::cout << "Mutex::lock" << std::endl;
}
void unlock()
{
std::cout << "Mutex::unlock" << std::endl;
}
};
template <class Object>
class ThreadSafeObject
{
mutable Mutex d_mutex;
Object d_object;
public:
struct Proxy
{
mutable Mutex *d_mutex;
Object *d_object;
Proxy(Mutex *mutex, Object *object)
: d_mutex(mutex)
, d_object(object)
{
d_mutex->lock();
}
Proxy(const Proxy& proxy)
: d_mutex(proxy.d_mutex)
, d_object(proxy.d_object)
{
proxy.d_mutex = NULL;
}
~Proxy()
{
if (d_mutex)
{
d_mutex->unlock();
}
}
Object *operator->()
{
return d_object;
}
};
struct ConstProxy
{
mutable Mutex *d_mutex;
const Object *d_object;
ConstProxy(Mutex *mutex, const Object *object)
: d_mutex(mutex)
, d_object(object)
{
d_mutex->lock();
}
ConstProxy(const ConstProxy& proxy)
: d_mutex(proxy.d_mutex)
, d_object(proxy.d_object)
{
proxy.d_mutex = NULL;
}
~ConstProxy()
{
if (d_mutex)
{
d_mutex->unlock();
}
}
const Object *operator->() const
{
return d_object;
}
};
Proxy operator->()
{
return Proxy(&d_mutex, &d_object);
}
ConstProxy operator->() const
{
return ConstProxy(&d_mutex, &d_object);
}
};
struct Foo
{
void foo()
{
std::cout << "Foo::foo" << std::endl;
}
};
int main()
{
ThreadSafeObject<Foo> myFoo;
myFoo->foo();
return 0;
}
Использует трюк оператора -> () (, когда operator-> не возвращает тип указателя, компилятор будет продолжать вызывать operator-> в возвращаемых значениях до тех пор, пока в конечном итоге не будет возвращен обычный тип указателя ), который выдаст следующий результат:
Mutex::lock
Foo::foo
Mutex::unlock
В общем случае, объект, который должен использоваться несколькими потоками, не долженвыставляя свои внутренние компоненты таким образом, было бы безопаснее, чтобы он принимал параметры и использовал свои внутренние значения для воздействия на них.