Я столкнулся с проблемой, которая кажется мне тревожной. Кажется, я нашел ситуацию, которая достаточно проста для обхода, но это может привести к проблемам, если: а) у меня потеря концентрации при программировании или б) кто-то еще начинает реализовывать мои интерфейсы и не знает, как с этим справиться эта ситуация.
Вот мои основные настройки:
У меня есть абстрактный класс, который я использую в качестве универсального интерфейса для нескольких типов данных. Я принял парадигму не виртуального публичного интерфейса (Sutter, 2001) вместе с блокировкой границ, чтобы обеспечить некоторую безопасность потоков. Пример класса интерфейса выглядел бы примерно так (я пропустил подробности о блокировке областей и реализации мьютекса, поскольку я не думаю, что они актуальны):
class Foo
{
public:
A( )
{
ScopedLock lock( mutex );
aImp( );
}
B( )
{
ScopedLock lock( mutex );
bImp( );
}
protected:
aImp( ) = 0;
bImp( ) = 0;
}
Затем пользователь должен реализовать aImp и bImp, в чем и заключается проблема. Если aImp выполняет какую-либо операцию, использующую bImp, это очень легко (и в некотором смысле почти логично) сделать это:
class Bar
{
protected:
aImp( )
{
...
B( );
...
}
bImp( )
{
...
}
}
Тупик. Конечно, простое решение этого состоит в том, чтобы всегда вызывать защищенные виртуальные функции, а не их открытые варианты (замените B () на bImp () в приведенном выше фрагменте). Но мне все еще кажется, что повесить себя легко, если я совершу ошибку или, что еще хуже, позволю другим повеситься.
Есть ли у кого-нибудь способ попытаться либо остановить реализацию абстрактного класса от вызова этих открытых функций во время компиляции, либо иным образом помочь избежать тупикового решения?
Только для ударов некоторые мьютексы допускают работу, которая позволит избежать проблем с блокировкой. Например, если я реализую это, используя функции Windows EnterCriticalSection и LeaveCriticalSection, проблем не возникает. Но я бы предпочел избегать специфической для платформы функциональности. В настоящее время я использую boost :: mutex и boost :: shared_mutex в своей реализации блокировки области действия, и, насколько я видел, она не пытается избежать тупика (что, я думаю, я почти предпочитаю).