-1

I'm trying to understand a pimple example from the "api design for c++" book (page 70).

// autotimer.h
class AutoTimer
{
public:
    explicit AutoTimer(const std::string &name);
    AutoTimer();
    // allow access from other classes/functions in autotimer.cpp
    class Impl;
private:
    Impl* mImpl;
}

From the text and example I would assume thats possible to access members of AutoTimer::Impl from free functions declared in autotimer.cpp like free_f() in the example below.

// autotimer.cpp
class AutoTimer::Impl
{
 public:
    std::string s;
}

void free_f(AutoTimer a){
    std::cout << a.mImpl->s << std::endl;
}

However, I can't get this to work. Sadly the book doesn’t give any further details. So, how can I fix free_f() to get access to the private members of Impl?

To be me more explicit, the comment (and first example)

// allow access from other classes/functions in autotimer.cpp

is straight from the book "api design for c++" and I want to know what it means.

user14419
  • 150
  • 1
  • 7
  • 2
    `a` is not a pointer. `mImpl` is a pointer. – juanchopanza Feb 21 '17 at 16:19
  • 1
    And `mImpl` is a `private` member of `AutoTimer`, so a free function wouldn't have access to it. – Fred Larson Feb 21 '17 at 16:22
  • ... unless it's a `friend` function. – Fred Larson Feb 21 '17 at 16:27
  • @FredLarson using a `friend` function is the only idea I could come up with too. But this needs to be declared in the public interface `autotimer.h` which didn't feel right. That's why I was hopping for some special trick. – user14419 Feb 21 '17 at 16:35
  • 2
    Since your `Impl` is hidden in `autotimer.cpp`, save for the announcement it somewhat-exists in the primary header, I have to ask. Why are *any* of the members of `Impl` private ? Re `free_f` access to `mImpl`, I don't see any way to do it without friending unless you provide getter-access. – WhozCraig Feb 21 '17 at 16:36
  • @WhozCraig you are right I have made the `Impl` members now public. The real issue is still the `mImpl` private declaration in `AutoTimer`. – user14419 Feb 21 '17 at 16:42
  • Just write a destructor for `AutoTimer` and use `free_f` within that constructor. – knivil Feb 21 '17 at 16:45
  • I dont see a `free_f` in the book. I see a `delete mImpl` in the destructor. And no, it is not possible to access private members ... and it has reasons. – knivil Feb 21 '17 at 16:53
  • @knivil the `free_f` is my example for a free function (I didn't catch the double meaning). So what is then the advantage to make the `class Impl` public? My understanding from the book was use make `class Impl` and `Impl* mImpl` private except when you want to access `mImpl` from a free function, then make `class Impl` public. I just don't see how this helps. – user14419 Feb 21 '17 at 17:04
  • Why on earth do you want to access `mImpl` from free functions? The interface is defined by `AutoTimer` and the Pimpl is just implementation that others should not have access to. Thats the hole point of Pimpl ... to have a really hidden implementation (just a pointer). – knivil Feb 21 '17 at 17:11
  • I use the Pimple to define a library API in `autotimer.h`. However, the library implementation needs access to the members of `mImpl`. – user14419 Feb 21 '17 at 17:17
  • If your `AutoTimer` is of standard layout type then you can `reinterpret_cast` a pointer of `AutoTimer` to its first member. That is what I do within a library. – knivil Feb 21 '17 at 17:27

1 Answers1

0

This is untested but should be legal C++ if your object is of standard layout type:

void free_f(AutoTimer a){
    Impl* tmp = *reinterpret_cast<Impl**>(&a);
    std::cout << tmp->s << std::endl;
}

And since you work with with Pimpl you should pass references or pointers of type AutoTimer. Otherwise a temporary object will destroy your implementation object on destruction.

http://en.cppreference.com/w/cpp/language/data_members#Standard_layout

knivil
  • 693
  • 3
  • 9
  • Thanks, that looks interesting! The casting looks a bit scary to me and I'm not yet sure if I like this solution. Do you have any examples/pointer that show that this is a common why to deal with Pimpl within a library? – user14419 Feb 21 '17 at 17:46
  • That is my way to deal with libraries / DLLs on windows. You can use friend functions or a dedicated `get_pimpl` member function to access your implementation. Both will extend the interface. I did not like that. I do not have any examples from other open source projects. I think the C++ community is very bussy with template super magic and do not need to cross boundaries of shared libraries. Also I do not use `std::string` or other runtime types in DLL interfaces to prevent some problems (e.g. side-by-side issues). – knivil Feb 21 '17 at 17:58