54

I'm flip-flopping between naming conventions for typedef'ing the boost::shared_ptr template. For example:

typedef boost::shared_ptr<Foo> FooPtr;

Before settling on a convention, I'd like to see what others use. What is your convention?

EDIT:

To those nesting the typedef inside Foo, doesn't it bother you that Foo is now "aware" of how it will be passed around? It seems to break encapsulation. How about this:

class Foo
{
public:
    typedef std::vector<Foo> Vector;
};

You wouldn't do this now, would you? :-)

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
  • 6
    To add to this question, how do people manage header inclusion when you declare such a typedef? Doesn't this wind up causing everyone to have to include Foo.h (rather than just saying "class Foo;"), leading to slow builds and possibly circular dependencies? – Rob Napier Apr 27 '10 at 00:12
  • 1
    I don't think that the nested typedef breaks encapsulation if you're using a factory. In fact, I'd say in that case it improves encapsulation in case the pointer type changes. – rlbond Apr 27 '10 at 00:15
  • @RobNapier `#include "foo_ptr.hpp"` ;-) – Emile Cormier Jan 26 '18 at 02:49
  • @RobNapier I call a macro [`MYLIB_DECLARE_PTRS(Foo);`](https://github.com/vgc/vgc/blob/master/libs/vgc/core/object.h#L35) to replace `class Foo;`. Inspired by [convention used in Pixar's USD](https://github.com/PixarAnimationStudios/USD/blob/master/pxr/base/lib/tf/declarePtrs.h) --- I loved this convention. – Boris Dalstein Jul 07 '18 at 20:53

16 Answers16

28

Answer: don't do it. It's convenient for you and nobody else. Say what you mean.

pdusen
  • 520
  • 2
  • 7
  • 18
  • 3
    Yup, I agree. Typedef'ing in this case only saves you typing and nothing else. It only adds one more indirection towards understanding the code. – Paul Manta Dec 01 '11 at 18:12
28

I'd like too add some options to this old question, even though they might be highly controversial…

Similar to OldPeculier's answer I like short type names that resemble standard pointers as closely as possible.

In a project that used shared_pointer almost everywhere, I used

typedef boost::shared_ptr<Foo> Foo_;

// usage examples:
Foo* myFoo0;
Foo_ myFoo1;

I took advantage of three things:

  1. That the underscore character somehow looks like an operator, yet is treated mostly like a letter, so that it can be part of an identifier (and I see no rule forbidding it at the end of the identifier).
  2. That I only needed to come up with one typedef.
  3. I prefer Foo* myFoo1; over Foo *myFoo1; for several reasons, and it matches nicely with Foo_ myFoo2.

When in need of typedefs for different kinds of smart pointers, I'd go for

typedef shared_ptr<Foo> Foo_S;
typedef weak_ptr<Foo>   Foo_W;
typedef unique_ptr<Foo> Foo_U;

// usage examples:
Foo*  myFoo2;
Foo_S myFoo3;
Foo_W myFoo4;
Foo_U myFoo5;

With increasing Unicode support in the standards and compiler implementations, I'd be tempted to try the following syntax, assuming that those star characters would be treated as a regular part of the type identifier. Of course this is only practical if all involved developers have a convenient text input method for this:

typedef shared_ptr<Foo> Foo★;
typedef weak_ptr<Foo>   Foo☆;
typedef unique_ptr<Foo> Foo✪;

// usage examples:
Foo* myFoo6;
Foo★ myFoo7;
Foo☆ myFoo8;
Foo✪ myFoo9;

(A quick test indicated that this does not actually work, at least with my build environment. But the same is true for Foo_ä.)

Lena Schimmel
  • 7,203
  • 5
  • 43
  • 58
  • 2
    As the author of this answer, I want to disclose that I posted a link to it on twitter with a screenshot of the last code example. The tweet gained high populartiy due to the hilarious look of the code - more than 150 retweets and over 50.000 views - so the relatively high number of upvotes might not be representative. – Lena Schimmel Jun 26 '17 at 09:58
  • Note that `int* a, b` might seem like `a` and `b` are both pointers to `int`s. However, that's not the case: only `a` is a ptr to `int`, `b` is just an `int`. That's why I prefer `int *a, b` which (may) help a bit more in avoiding confusion. One more thing: if you have `typedef int *PTR_INT;` and `PTR_INT a, b` then both `a` and `b` are `PTR_INT` i.e. pointers to `int`s. – Milan Nov 11 '21 at 17:09
15

My preference:

class Foo
{
public:

    typedef boost::shared_ptr<Foo> SharedPointer;
};

The problem with just FooPtr is that you may have different types of pointers (e.g., weak_ptrs). I also don't much care for abbreviations, but that's another matter altogether.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 2
    As it's pointed out in the comments, this creates a problem with header inclusion. How would you use `Foo::SharedPointer` in a header file without including `Foo.h`? – betabandido Sep 17 '13 at 22:19
5

Personally, in the code I'm responsible for, you'd typically see a FooPtr typedef'd at the same namespace scope as Foo and Foo would contain a generically named 'SmartPtr' typedef to the same type as FooPtr. Having FooPtr allows for easy an non-verbose manual usage. having the nested typedef for 'SmartPtr' or some quivalent allows for easy generic usage in templates, macros, etc. without having to know that actual type of the smart pointer.

Also, I'd suggest adding a 'subjective' tag to this question.

Nathan Ernst
  • 4,540
  • 25
  • 38
  • I thought meta-tags like subjective were discouraged now - http://blog.stackoverflow.com/2010/08/the-death-of-meta-tags/ – SCFrench Apr 22 '11 at 12:03
4

I have used both the outer and encapsulated typedef, but ended up with the first,

typedef boost::shared_ptr<Foo> FooPtr; 

solely because in combined expressions this looks cleaner than Foo::Ptr.

Doesn't it bother you that Foo is now "aware" of how it will be passed around?

Often enough, these classes are creatable through a factory method only:

struct Foo
{
     static FooPtr Create() { return FooPtr(new Foo); }

   protected:
     Foo() {}
}

That's kind of "stronger" than encapsulating the typedef, yet a very common pattern.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
peterchen
  • 40,917
  • 20
  • 104
  • 186
4

I'm generally not a fan of very short identifiers, but this is one case where I'll use them.

class Foo
{
public:
    typedef std::shared_ptr<Foo> p;
};

This enables shared_ptr to resemble ordinary pointers as closely as possible without risk of confusion.

Foo* myFoo;
Foo::p myFoo;

And as for breaking encapsulation—no, typedefing the shared_ptr type within the class doesn't break encapsulation any more than typedefing it outside of the class. What meaning of "encapsulation" would it violate? You're not revealing anything about the implementation of Foo. You're just defining a type. This is perfectly analogous to the relationship between Foo* and Foo. Foo* is a certain kind of pointer to Foo (the default kind, as it happens). Foo::p is another kind of pointer to Foo. You're not breaking encapsulation, you're just adding to the type system.

OldPeculier
  • 11,049
  • 13
  • 50
  • 76
2

I'm not a big fan of Hungarian naming conventions, I usually use:

typedef boost::shared_ptr<Foo> FooSharedPtr;

Detailed enough to be clear but short enough to not be a huge hassle. In any case, I would definitely indicate it's specifically a shared pointer, especially if you're not the only one who's going to be using that type in the future.

Nate
  • 2,462
  • 1
  • 20
  • 28
2

I usually encapsulate the the typedef inside the class. The reason is that we have some memory sensitive code, and it makes it easy to switch between boost::shared_ptr and boost::intrusive_ptr Since intrusive_ptr is something that the class needs to support, it makes sense to me to have the knowledge of which shared pointer to use be wrapped up in the class.

KeithB
  • 16,577
  • 3
  • 41
  • 45
1

It's nice when it ends with _t.

class Bar
{
public:
    typedef boost::shared_ptr<Bar> Ptr_t;
};
alex vasi
  • 5,304
  • 28
  • 31
1

My first response is to ask, "Why typedef that?"

In reply to your edit: Actually that's a rather interesting approach that could be useful in many situations. Using it to go back to your original question you might have:


struct object
{
  typedef object* ptr_t;
  typedef shared_ptr<object> shared_ptr_t;
  typedef weak_ptr<object> weak_ptr_t;
  typedef unique_ptr<object> unique_ptr_t;
  etc...
}
Edward Strange
  • 40,307
  • 7
  • 73
  • 125
1

How about:

template <typename T>
class Shared
{
    public: 
        typedef std::shared_ptr<T> Ptr; // or boost::shared_ptr if you will
};

Then allowing any Shared class to have their own Ptr object, as in:

class myClass : public Shared<myClass>
{
};

int main()
{
    myClass::Ptr object;
    //...
    object->foo();
}
Sergio Basurco
  • 3,488
  • 2
  • 22
  • 40
1
  typedef shared_ptr<Foo> sptr_Foo;
  typedef weak_ptr<Foo>   wptr_Foo;
  typedef unique_ptr<Foo> uptr_Foo;
user846566
  • 373
  • 1
  • 3
  • 12
0

This was one of the conventions I was flip-flopping to:

typedef boost::shared_ptr<Foo> FooProxy;

...seeing that boost::shared_ptr is an application of the Proxy pattern.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
0

I would get rid of the namespace instead of shortening the type.

using boost::shared_ptr; // or using std::shared_ptr, 
struct Foo
{
    shared_ptr<Foo> impl;
};

Which has the bonus that you can change between implementations easily.

If that is still too long (I think it is just right):

using boost::shared_ptr;
template<class T> using sptr = shared_ptr<T>;
struct Foo
{
    sptr<Foo> impl;
};
alfC
  • 14,261
  • 4
  • 67
  • 118
0

typedef boost::shared_ptr&lt;MyClass> MyClass$;

Coding Mash
  • 3,338
  • 5
  • 24
  • 45
Hideki
  • 1
0
class foo;

typedef boost::shared_ptr<foo> foo_p;
typedef boost::weak_ptr<foo> foo_wp;
Navrocky
  • 1,670
  • 1
  • 13
  • 10