0

When creating a class that is composed of other classes, is it worthwhile reducing dependencies (and hence compile times) by using pointers rather than values?

For example, the below uses values.

// ThingId.hpp
class ThingId
{
    // ...
};

// Thing.hpp
#include "ThingId.hpp"
class Thing
{
public:
    Thing(const ThingId& thingId);
private:
    ThingId thingId_;
};

// Thing.cpp
#include "Thing.hpp"
Thing::Thing(const ThingId& thingId) :
    thingId_(thingId) {}

However, the modified version below uses pointers.

// ThingId.hpp
class ThingId
{
    // ...
};

// Thing.hpp
class ThingId;
class Thing
{
public:
    Thing(const ThingId& thingId);
private:
    ThingId* thingId_;
};

// Thing.cpp
#include "ThingId.hpp"
#include "Thing.hpp"
Thing::Thing(const ThingId& thingId) :
    thingId_(new ThingId(thingId)) {}

I've read a post that recommends such an approach, but if you have a large number of pointers, there'll be a large number of new calls, which I imagine would be slow.

magnus
  • 4,031
  • 7
  • 26
  • 48
  • "is it worthwhile reducing dependencies (and hence compile times) by using pointers rather than values?" - I don't see how using pointers "reduces dependencies" - nor how it has any relation to compile time. – Dai Mar 15 '16 at 00:42
  • There's nothing about a pointer that requires a `new` call to be made. I can write a bunch of code, with pointers all over the place, and not a single `new` call. – Sam Varshavchik Mar 15 '16 at 00:42
  • @Dai: You can forward declare the pointee type rather than `#include`ing the entire header in which the type is fully defined. – Lightness Races in Orbit Mar 15 '16 at 00:42
  • @SamVarshavchik: The code in the question is not an example of code in which a pointer to an automatic-storage-duration variable would be safe. There are lifetime considerations. The OP is generally correct that this approach would inevitably lead to more (probably excess) dynamic allocations. – Lightness Races in Orbit Mar 15 '16 at 00:43
  • @Dai Obviously using pointers reduces compile time dependencies from class implementation changes if you do not publish the implementation; that in turn prohibits using plain objects (their size and layout is not known to the using code). It's simple pimpl. – Peter - Reinstate Monica Mar 15 '16 at 01:10
  • @SamVarshavchik The pimpl idiom usually means more dynamic allocations. You can provide your own allocator, or rely on static objects, but the client code can not generally create objects with automatic storage duration. – Peter - Reinstate Monica Mar 15 '16 at 01:12

2 Answers2

3

This is what most people call the Pimpl idiom (http://c2.com/cgi/wiki?PimplIdiom).

Simple Answer

I highly suspect that you do not have a good use case for this and should avoid it at all cost.

My Experience

The main way that Pimpl has ever been useful for me is to make an implementation detail private. It achieves this because you do not need to include the headers of your dependencies, but can simply forward declare their types.

Example

If you want to provide an SDK to someone which uses some boost library code under the hood, but you want the option of later swapping that out for some other library without causing any problem for the consumer of your SDK, then Pimpl can make a lot of sense.

It also helps create a facade over an implementation so that you have control over the entire exposed public interface, rather than exposing the library you implicitly depend on, and consequently its entire interface that you don't have control over and may change, may expose too much, may be hard to use, etc.

Nicholas Smith
  • 975
  • 7
  • 18
2

If your program doesn't warrant dynamic allocation, don't introduce it just for the sake of project organisation. That would definitely be a false economy.

What you really want to do is attempt to reduce the number of inter-class dependencies entirely.

However, as long as your coupling is sensible and tree-like, don't worry too much about it. If you're using precompiled headers (and you are, right?) then none of this really matters for compilation times.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I think the issue is also large dependency trees. Small, possibly irrelevant changes in some header may cause most of the project to recompile. For large projects that may be prohibitive, for example prevent nightly builds plus tests. That was a question when I applied for a job at Star Division (Star Office, later OpenOffice) in Hamburg: "If you want to add a virtual function to a polymorphic class without recompiling all files which use this class; where do you place the new function in the class declaration?" (At the end, because all earlier offsets in the VTable don't change.) – Peter - Reinstate Monica Mar 15 '16 at 01:07
  • "What you really want to do is attempt to reduce the number of inter-class dependencies entirely." Any references on approaches to doing this? – magnus Mar 15 '16 at 01:21