views:

150

answers:

3

I've just started working on a new codebase where each class contains a shared_ptr typedef (similar to this) like:

typedef boost::shared_ptr<MyClass> Ptr;

Is the only purpose to save typing boost::shared_ptr?

If that is the case, is the only reason not to do

#define Ptr boost::shared_ptr 

in one common header the general problems with #define? Then you can do:

Ptr<MyClass> myClass(new MyClass);

which is no more typing than

MyClass::Ptr myClass(new MyClass);

and saves the Ptr definition in each class.

+2  A: 

Disadvantages of defines have been discussed extensively all over the web. For example, it will collide with Ptr in another namespace:

someLibrary::Ptr somethingElse -> somelibrary::crap

If typing boost::shared_ptr really annoys, you can be using namespace boost. It will preserve the readability (people really want to know it's boost shared_ptr).

Another thing I can suggest you is a series of typedefs. In my company, there's a convention that MyClassPtr is a typedef to boost::shared_ptr.

Pavel Radzivilovsky
I should have made my question clearer about the problems with #define (have now edited it to do that).I would agree with you that using namespace boost seems to be preferable to save typing and am wondering why the typedef Ptr idiom is commonly used.
danio
+7  A: 

A macro (#define) is always defined globally. This means that every use of the 'string' Ptr (even a variable) will be replaced by the macro.

The typedef can be placed in a class, in a namespace, ... so you have much better control over it.

EDIT: another advantage is that you can haver different Ptr types in different classes, e.g.

  • ClassX::Ptr is a boost shared_ptr
  • ClassY::Ptr can be another shared_ptr
  • ClassZ::Ptr can be a simple "Class Z *" pointer

If these classes are then used in templated code, you can use T::Ptr as a type of pointer to the class, and the template will use the most-appropriate pointer for the class.

Patrick
Having the class define its own meaning for Ptr seems dangerous to me. e.g. ClassZ::Ptr will need to be explicitly deleted, whereas the others don't and how is client code to know this?
danio
Maybe the "Class Z *" pointer case is a bad example, but the argument remains valid for other kinds of smart pointers. I wanted to give an example where it is the class itself that determines the best way to point to it, rather than the user of the class.
Patrick
@Patrick: it's not a bad example. You're copying a pointer, so only one of the holders of a copy will have to perform a `delete`. Traditionally the one which owns the resource. It's fine to pass copies to others and not have them worry about it, though of course you'd better be sure the object will be alive as long as they intend to use it.
Matthieu M.
+1  A: 

Is the only purpose to save typing boost::shared_ptr?

Yes, pretty much. Well, not to save typing per se, it's to improve readability. But I think that's kind of what you meant.

Compare these and see which you like. There's no correct answer, other than to be aware of problems with macros and namespace clutter.

boost::shared_ptr<Foo> func (boost::shared_ptr<Foo> a, boost::shared_ptr<Foo> b);

shared_ptr<Foo> func (shared_ptr<Foo> a, shared_ptr<Foo> b);

Ptr<Foo> func (Ptr<Foo> a, Ptr<Foo> b);

Foo::ptr func (Foo::ptr a, Foo::ptr b);

FooPtr func (FooPtr a, FooPtr b);

Foo* func (Foo* a, Foo* b);
John