1

I've two classes that implement PIMPL: State and StateMachine.

They implement Private::State and Private::StateMachine.

Private::StateMachine has an "addState(Private::State &)" method. I want to write the addState() method into its PIMPL class, in order to do

StateMachine machine;
State        state;

machine.addState(state);

How can I pass to Private::StateMachine inside StateMachine the object Private::State pimpled in State?

StateMachine.h

#include <memory>

class State;
namespace Private {
  class StateMachine;
} // namespace Private

class StateMachine
{
public:
  StateMachine();
  ~StateMachine();

  // want to add this
  void addState(const State &state);

private:
  std::unique_ptr<Private::StateMachine> m_stateMachine;
};

State.h

#include <memory>

namespace Private {
class State;
} // namespace Private

namespace StateMachine {

class State
{
public:
  State();
  ~State();

private:

  std::unique_ptr<Private::State> m_state;
};
Jepessen
  • 11,744
  • 14
  • 82
  • 149

1 Answers1

1

There are probably an unlimited number of answers to this question.

Here are some questions to guide your thinking:

  1. What should be the effect of copying a State object? Should the internal Private::State be copied also?
  2. Should copies be disallowed (preferring moves)? In which case you'll want to dump user-defined constructors allowing the compiler to generate moves for you.
  3. Assuming (2), should your Private::StateMachine be storing a unique_ptr<Private::State> or a unique_ptr<State>? This gets tricky because if you want direct interaction between state and machine behind the pimpl you probably want to store a unique_ptr<Private::State> to avoid exposing private operations in the ::State interface. If you ever want to deliver a State back to user code then you'll have to rebuild the ::State handle. This might argue for a non-owning version of ::State.
  4. What is the intent of the use of pimpl? Is the idea that State is a handle to a Private::State? Is it reasonable to have the concept of a 'null handle' (for example as a result of a move)? Should 2 handles share the same state during a copy (argues for shared_ptr)? and so on.

In summary, there is an answer but it depends entirely on the synopsis of StateMachine, State and their desired interaction in user code. I would suggest that you start there - design the use cases and observe their effects on copy, move, assignment etc. This should lead you to a natural implementation.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • `StateMachine` and `State` should be not copyable. With pimpl I want only to hide classes implementations. – Jepessen Jan 12 '15 at 15:48
  • in that case, what should addState() do with the state you gave it? Will it make a copy of something in the `Private::State` impl? – Richard Hodges Jan 12 '15 at 15:51
  • No it must read some properties from Private::State and perform a couple of operations without copying or moving it. – Jepessen Jan 12 '15 at 15:56
  • In that case I would suggest that objects in the `Private::` namespace only interact with other objects in the `Private::` namespace. StateMachine::addState would need to defer to `Private::StateMachine::addState(const Private::State&)` – Richard Hodges Jan 12 '15 at 16:44
  • And how can I expose `Private::State` of `State` class without exposing the opaque pointer to public interface? – Jepessen Jan 13 '15 at 07:35
  • I've declared `::StateMachine` as a friend class inside `::State`. In this way I can see `::State` opaque pointer inside `::StateMachine` ad it seems to work. It's a good practice to do it this way? – Jepessen Jan 13 '15 at 08:13
  • Yes that's reasonable – Richard Hodges Jan 13 '15 at 08:40