cross platform: any alternatives to pimpl?

S

Simon Elliott

I want to design a class which will encapsulate some system specific
representation, in this case time structs:


#if unix_implementation

#include <time.h>
class Cfoo
{
private:
timespec someTime_;
public:
// various public methods
};

#endif

#if w32_implementation

#include <windows.h>
class Cfoo
{
private:
SYSTEMTIME someTime_;
public:
// various public methods
};

#endif

I'd like to have a single header with no #if/#ifdef and with no system
specific headers being included (eg windows.h).

The obvious way of doing this is with a pimpl, keeping all the system
specific things in the implementation class. However, in some
implementations, someTime_ will be an unsigned long. I don't want the
overhead of a pimpl (dynamic allocations and forwarding functions) for
the sake of managing 4 bytes of data. Nor do I want to get involved
with fixed-sized allocators.

Is there a better way of doing this? It occurs to me that there ought
to be a way of doing this with templates, since template code is only
compiled as needed.
 
I

int2str

Simon said:
I'd like to have a single header with no #if/#ifdef and with no system
specific headers being included (eg windows.h).
...
The obvious way of doing this is with a pimpl, keeping all the system
specific things in the implementation class. However, in some
implementations, someTime_ will be an unsigned long.

The keyword here is "some". Since it may be different in "others" and
even different in the future, the pimpl idiom is great for keeping the
implementation details out of the header and being ready for the future
(or other platforms).
I don't want the overhead of a pimpl (dynamic allocations and
forwarding functions) for the sake of managing 4 bytes of data.

The "overhead" is rather minimal - especially when you deal with 4
bytes of data as you say. Also, are you sure that this part of your
program will be "time critical"? Sounds a lot like premature
optimization to me, which you should shy away from.

The benefit of a clean header file and implementation freedom far
outweight any overhead IMHO.
Is there a better way of doing this?

For API clarity, platform independence and future proofing - no! ;)

Cheers,
Andre
 
K

Kaz Kylheku

Simon said:
I want to design a class which will encapsulate some system specific
representation, in this case time structs:


#if unix_implementation

#include <time.h>
class Cfoo
{
private:
timespec someTime_;
public:
// various public methods
};

#endif

#if w32_implementation

#include <windows.h>
class Cfoo
{
private:
SYSTEMTIME someTime_;
public:
// various public methods
};

#endif

I'd like to have a single header with no #if/#ifdef and with no system
specific headers being included (eg windows.h).

The obvious way of doing this is with a pimpl, keeping all the system
specific things in the implementation class.

class Cfoo
{
private:
union {
unsigned long ul;
CfooImpl *ptr;
} impl;
public:
// Some public methods ...
};

The Windows implementation of Cfoo will use a class derived from
CfooImpl to wrap a SYSTEMTIME struct. The CfooImpl pointer is stored in
the union member Cfoo::impl.ptr.


The unix implementation of Cfoo can use the union member Cfoo::impl.ul
to store the epoch time.

Since it's a union, you save space without #ifdef.

Off topic remark: do you think you should use analogous time
representations? The Win32 analogy of the 32 bit unix time is the 64
bit hundreds of nanoseconds thing (FILETIME) since some date in 16xx.
SYSTEMTIME gives you a ``broken down'' time, similar to the standard C
``struct time'' which you can use in Windows or POSIX environments.

It would make sense to either use a ``broken down'' time representation
on both platforms, where you can extract the year, month, day, etc, or
use a numeric representation on both platforms which lends itself to
displacement arithmetic. The similarity in semantics will probably be
easier to maintain the classes in parallel that way, since similar
things will be done in similar ways.
 
K

Kaz Kylheku

Simon said:
The obvious way of doing this is with a pimpl, keeping all the system
specific things in the implementation class. However, in some
implementations, someTime_ will be an unsigned long. I don't want the
overhead of a pimpl (dynamic allocations and forwarding functions) for
the sake of managing 4 bytes of data. Nor do I want to get involved
with fixed-sized allocators.

Is there a better way of doing this? It occurs to me that there ought
to be a way of doing this with templates, since template code is only
compiled as needed.

class Cfoo
{
private:
union {
unsigned long ul;
CfooImpl *ptr;
} impl;
public:
// Some public methods ...
};

The Windows implementation of Cfoo will use a class derived from
CfooImpl to wrap a SYSTEMTIME struct. The CfooImpl pointer is stored in

the union member Cfoo::impl.ptr.

The implementation of Cfoo which packs time into an unsigned long can
use the union member Cfoo::impl.ul.

Since it's a union, you save space without #ifdef.
 
S

Simon Elliott

class Cfoo
{
private:
union {
unsigned long ul;
CfooImpl *ptr;
} impl;
public:
// Some public methods ...
};

The Windows implementation of Cfoo will use a class derived from
CfooImpl to wrap a SYSTEMTIME struct. The CfooImpl pointer is stored
in the union member Cfoo::impl.ptr.


The unix implementation of Cfoo can use the union member Cfoo::impl.ul
to store the epoch time.

Interesting idea. I hadn't considered using a union.
Since it's a union, you save space without #ifdef.

Off topic remark: do you think you should use analogous time
representations? The Win32 analogy of the 32 bit unix time is the 64
bit hundreds of nanoseconds thing (FILETIME) since some date in 16xx.
SYSTEMTIME gives you a ``broken down'' time, similar to the standard C
``struct time'' which you can use in Windows or POSIX environments.

It would make sense to either use a ``broken down'' time
representation on both platforms, where you can extract the year,
month, day, etc, or use a numeric representation on both platforms
which lends itself to displacement arithmetic. The similarity in
semantics will probably be easier to maintain the classes in parallel
that way, since similar things will be done in similar ways.

Absolutely. I used SYSTEMTIME as a (bad) example of what I was trying
to achieve. For W32 I may well just use GetTickCount() as the elapsed
time will never exceed its limits.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top