Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 578
rubenvb Avatar asked Aug 27 '16 15:08

rubenvb


People also ask

How do I implement the observer design pattern in net?

In .NET, the observer design pattern is applied by implementing the generic System.IObservable<T> and System.IObserver<T> interfaces. The generic type parameter represents the type that provides notification information.

How to provide current state information to observers in net?

In this method call, the provider can also provide current state information to observers. In .NET, the observer design pattern is applied by implementing the generic System.IObservable<T> and System.IObserver<T> interfaces. The generic type parameter represents the type that provides notification information.

What is observers pattern in Salesforce?

Observer Design Pattern. The observer design pattern enables a subscriber to register with and receive notifications from a provider. It is suitable for any scenario that requires push-based notification. The pattern defines a provider (also known as a subject or an observable) and zero, one, or more observers.

What is the use of const cast in C++?

2) const_cast can be used to pass const data to a function that doesn’t receive const. For example, in the following program fun () receives a normal pointer, but a pointer to a const can be passed with the help of const_cast.


2 Answers

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).


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

like image 140
πάντα ῥεῖ Avatar answered Oct 23 '22 13:10

πάντα ῥεῖ


There are two straightforward ways to fix this:

  1. const_cast the lists inside connect.
  2. Make the lists mutable.

In fact there is a third choice (which is a general purpose would-be workaround, had C++ not provided the mutable keyword) - you can move the concerned data out of the syntactical object:

class X
{
    mutable int           i1_;

    // Data pointed to by i2_ semantically belongs to this object
    // but doesn't constitute a syntactical part of it so it is not
    // subject to const-correctness checks by the compiler.
    std::unique_ptr<int>  i2_;

public:
    void constFunc() const {
        i1_  = 123;
        *i2_ = 456;
    }
};

Despite the availability of this additional option, I still concur with πάντα ῥεῖ's answer that the mutable keyword is the right choice for such cases. It explicitly documents in a standardized way (e.g. allows to be grepped) that the conceptually const operations of this class may not be technically non-mutating. This is good to know, for example, when being concerned with thread safety of const functions of the class.

like image 37
Leon Avatar answered Oct 23 '22 12:10

Leon