rubenvb rubenvb - 3 months ago 21
C++ Question

Implementing signals (Observer pattern): is mutable or const_cast necessary?

I'm implementing my very own

signal
/slot (observer pattern, Qt style) mechanism so I can have a
property
that notifies ... stuff... that is has changed.

I think C++11 provides everything necessary to make a very succint and featureful implementation possible. The "issue" I'm running into is if I want to "connect" to a signal of a
const
object, I need the
signal::connect
function to be const, but modify the list of callbacks/observers. There are two straightforward ways to fix this:


  1. const_cast
    the lists inside
    connect
    .

  2. Make the lists
    mutable
    .



Both seem to me like the same thing (and this has been asked before, e.g. in this question), and perfectly fine logically, but stylistically questionable. Hence the question. Is there a way around this or is this a truly justified use of
const_cast
/
mutable
?

Some prelimenary code as I have it now:

template<typename... ArgTypes>
class signal
{
public:
template<typename Callable>
void connect(Callable&& callback) const
{
std::lock_guard<std::mutex> lock(slots_mutex);
slots.emplace_back(callback);
}

void emit(ArgTypes... arguments) const
{
std::lock_guard<std::mutex> lock(slots_mutex);
for(auto&& callback : slots)
{
callback(arguments...);
}
}

private:
// mutable here allows to connect to a const object's signals
mutable std::vector<std::function<void(ArgTypes...)>> slots;
std::mutex slots_mutex;

};


Note I haven't tested this code; this is just a reflection of my current state of mind.

Answer

mutable is usually the better choice for such cases.

Avoid (const) casting whenever you can, it's prone for hitting undefined behavior, while mutable is guaranteed to be not1).


1 mutable class members are guaranteed not to go to emitted codes .text segment for instance.

Comments