What's your convention for typedef'ing sha

2019-01-21 12:51发布

问题:

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? :-)

回答1:

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_ä.)



回答2:

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



回答3:

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.



回答4:

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.



回答5:

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.



回答6:

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.



回答7:

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.



回答8:

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.



回答9:

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...
}


回答10:

  typedef shared_ptr<Foo> sptr_Foo;
  typedef weak_ptr<Foo>   wptr_Foo;
  typedef unique_ptr<Foo> uptr_Foo;


回答11:

It's nice when it ends with _t.

class Bar
{
public:
    typedef boost::shared_ptr<Bar> Ptr_t;
};


回答12:

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.



回答13:

class foo;

typedef boost::shared_ptr<foo> foo_p;
typedef boost::weak_ptr<foo> foo_wp;


回答14:

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



回答15:

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();
}


回答16:

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;
};


回答17:

I've used the following: typedef boost::shared_ptr<Foo> Foo_rcptr_t;

This clearly indicates that it is a refcounted ptr.