wake-up-neo.com

Was ist Ihre Konvention zur Typisierung von shared_ptr?

Ich wechsle zwischen den Namenskonventionen für die Typisierung der Vorlage boost :: shared_ptr. Zum Beispiel:

typedef boost::shared_ptr<Foo> FooPtr;

Bevor ich mich auf eine Convention einlasse, würde ich gerne sehen, was andere nutzen. Was ist Ihre Konvention?

BEARBEITEN:

Stört es Sie nicht, dass Foo jetzt "weiß", wie es weitergegeben wird, wenn die typedef in Foo nisten? Es scheint die Kapselung zu durchbrechen. Wie wäre es damit:

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

Das würdest du jetzt nicht tun, oder? :-)

44
Emile Cormier

Ich möchte dieser alten Frage auch einige Optionen hinzufügen, auch wenn sie höchst kontrovers sein könnten ...

Ähnlich wie Antwort von OldPeculier Ich mag kurze Typnamen, die Standardzeiger so ähnlich wie möglich sind.

In einem Projekt, in dem shared_pointer fast überall verwendet wurde, habe ich verwendet

typedef boost::shared_ptr<Foo> Foo_;

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

Ich habe drei Dinge ausgenutzt:

  1. Dass das Unterstrichzeichen irgendwie wie ein Operator aussieht, jedoch meistens wie ein Buchstabe behandelt wird, sodass es Teil eines Bezeichners sein kann (und ich sehe keine Regelverbot am Ende des Bezeichners).
  2. Dass ich nur mit one typedef kommen musste.
  3. Ich ziehe Foo* myFoo1; dem Foo *myFoo1; aus verschiedenen Gründen vor, und es passt gut zu Foo_ myFoo2.

Wenn Typedefs für verschiedene Arten von intelligenten Zeigern benötigt werden, würde ich dies tun

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;

Mit zunehmender Unicode-Unterstützung in den Standards und Compilerimplementierungen wäre ich versucht, die folgende Syntax auszuprobieren, vorausgesetzt, dass diese Sternzeichen als regulärer Teil der Typkennung behandelt werden. Dies ist natürlich nur dann praktisch, wenn alle beteiligten Entwickler über eine bequeme Texteingabemethode verfügen:

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;

(Ein Schnelltest ergab, dass dies zumindest in meiner Build-Umgebung nicht wirklich funktioniert. Das gleiche gilt jedoch für Foo_ä.)

27
Lena Schimmel

Antwort: Tu es nicht. Es ist praktisch für dich und niemanden sonst. Sag was du meinst.

25
pdusen

Meine Vorliebe:

class Foo
{
public:

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

Das Problem mit nur FooPtr ist, dass Sie unterschiedliche Zeigertypen haben können (z. B. weak_ptrs). Abkürzungen sind mir auch egal, aber das ist eine ganz andere Sache.

15
James McNellis

Persönlich würde in dem Code, für den ich verantwortlich bin, normalerweise ein FooPtr-Typedef'd im selben Namespace-Bereich angezeigt, in dem Foo und Foo einen generisch mit dem Namen "SmartPtr" bezeichneten Typedef mit demselben Typ wie FooPtr enthalten. Mit FooPtr ist eine einfache, nicht ausführliche manuelle Verwendung möglich. Wenn Sie das verschachtelte Typedef für 'SmartPtr' oder ein Quivalent verwenden, können Sie die generische Verwendung in Vorlagen, Makros usw. problemlos durchführen, ohne den tatsächlichen Typ des intelligenten Zeigers kennen zu müssen.

Ich würde auch vorschlagen, diese Frage mit einem "subjektiven" Tag zu versehen.

5
Nathan Ernst

Ich habe sowohl das äußere als auch das gekapselte Typedef verwendet, aber am Ende bin ich mit 

typedef boost::shared_ptr<Foo> FooPtr; 

nur weil dies in kombinierten Ausdrücken sauberer ist als Foo::Ptr.

Stört es dich nicht, dass Foo jetzt weiß, wie es weitergegeben wird?

Oft genug können diese Klassen nur durch eine Factory-Methode erstellt werden:

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

   protected:
     Foo() {}
}

Das ist irgendwie "stärker" als das Einkapseln des Typedefs, jedoch ein sehr verbreitetes Muster.

4
peterchen

Normalerweise kapsle ich den typedef in der Klasse. Der Grund ist, dass wir über einen speicherempfindlichen Code verfügen, der das Wechseln zwischen boost::shared_ptr und boost::intrusive_ptr Erleichtert. Da intrusive_ptr etwas ist, das die Klasse unterstützen muss, Es ist für mich sinnvoll, zu wissen, welcher gemeinsame Zeiger in der Klasse verwendet wird.

2
KeithB

Ich bin kein großer Fan von ungarischen Namenskonventionen und verwende normalerweise:

typedef boost::shared_ptr<Foo> FooSharedPtr;

Detailliert genug, um klar zu sein, aber kurz genug, um keinen großen Ärger zu verursachen. In jedem Fall würde ich definitiv darauf hinweisen, dass es sich speziell um einen gemeinsamen Zeiger handelt, insbesondere wenn Sie nicht der einzige sind, der diesen Typ in der Zukunft verwenden wird.

2
Nate

Ich bin generell kein Fan von sehr kurzen Identifikatoren, aber in diesem Fall benutze ich sie.

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

Dies ermöglicht shared_ptr, möglichst nahe an normalen Zeigern zu sein, ohne dass Verwirrung entsteht.

Foo* myFoo;
Foo::p myFoo;

Und was das Brechen der Einkapselung angeht - Nein, die Typisierung des Typs shared_ptr innerhalb der Klasse zerstört die Einkapselung nicht mehr als die Eingabe außerhalb der Klasse. Welche Bedeutung von "Einkapselung" würde es verletzen? Sie verraten nichts über die Implementierung von Foo. Sie definieren nur einen Typ. Dies ist vollkommen analog zu der Beziehung zwischen Foo * und Foo. Foo * ist eine bestimmte Art von Zeiger auf Foo (die Standardart, wie es passiert). Foo :: p ist eine andere Art von Zeiger auf Foo. Sie brechen nicht die Kapselung, Sie fügen nur das Typsystem hinzu.

2
OldPeculier
  typedef shared_ptr<Foo> sptr_Foo;
  typedef weak_ptr<Foo>   wptr_Foo;
  typedef unique_ptr<Foo> uptr_Foo;
1
user846566

Meine erste Antwort ist zu fragen: "Warum typedef das?"

Antwort auf Ihre Bearbeitung: Eigentlich ist das ein ziemlich interessanter Ansatz, der in vielen Situationen nützlich sein könnte. Verwenden Sie es, um zu Ihrer ursprünglichen Frage zurückzukehren, die Sie möglicherweise haben:


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...
}
1
Crazy Eddie

Ich würde den Namespace loswerden, anstatt den Typ zu verkürzen.

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

Was hat den Vorteil, dass Sie leicht zwischen Implementierungen wechseln können.

Wenn das noch zu lang ist (ich denke es ist genau richtig):

using boost::shared_ptr;
template<class T> using sptr = shared_ptr<T>;
struct Foo
{
    sptr<Foo> impl;
};
0
alfC

Es ist schön, wenn es mit _t endet.

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

Wie wäre es mit:

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

Dann kann jeder Shared-Klasse ein eigenes Ptr-Objekt zugewiesen werden, wie in:

class myClass : public Shared<myClass>
{
};

int main()
{
    myClass::Ptr object;
    //...
    object->foo();
}
0
Sergio Basurco

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

0
Hideki

Dies war eine der Konventionen, auf die ich mich umdrehte:

typedef boost::shared_ptr<Foo> FooProxy;

... zu sehen, dass boost::shared_ptr eine Anwendung des Proxy - Musters ist.

0
Emile Cormier
class foo;

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