Après avoir lu cette réponse , il semble que c'est une meilleure pratique d'utiliser autant que possible des pointeurs intelligents et de réduire au minimum l'utilisation de pointeurs "normaux".
Est-ce vrai?
Après avoir lu cette réponse , il semble que c'est une meilleure pratique d'utiliser autant que possible des pointeurs intelligents et de réduire au minimum l'utilisation de pointeurs "normaux".
Est-ce vrai?
Non, il n'est pas vrai. Si une fonction a besoin d'un pointeur et n'a rien à voir avec la propriété, alors je crois fermement qu'un pointeur normal devrait être adoptée pour les raisons suivantes:
shared_ptr
, alors vous ne serez pas en mesure de passer, disons, scoped_ptr
La règle serait ce - si vous savez qu'une entité doit prendre un certain type de propriété de l'objet, toujours utiliser des pointeurs intelligents - celui qui vous donne le type de propriété que vous avez besoin. Si il n'y a pas de notion de propriété, ne jamais utiliser des pointeurs intelligents.
Exemple1:
void PrintObject(shared_ptr<const Object> po) //bad
{
if(po)
po->Print();
else
log_error();
}
void PrintObject(const Object* po) //good
{
if(po)
po->Print();
else
log_error();
}
Exemple2:
Object* createObject() //bad
{
return new Object;
}
some_smart_ptr<Object> createObject() //good
{
return some_smart_ptr<Object>(new Object);
}
À l'aide de pointeurs intelligents pour gérer la propriété est le droit chose à faire. À l'inverse, à l'aide de matières pointeurs partout où la propriété n'est pas une question qui est pas mal.
Voici quelques parfaitement légitime utilisation brute des pointeurs (rappelez-vous, il est toujours supposé qu'ils sont non-propriétaire):
où ils sont en concurrence avec des références
0
pendant la durée de vie de l'objetstd::bind
utilise une convention où les arguments qui sont passés sont copiés dans la foncteur; toutefois std::bind(&T::some_member, this, ...)
seulement fait une copie du pointeur de la souris alors qu' std::bind(&T::some_member, *this, ...)
des copies de l'objet; std::bind(&T::some_member, std::ref(*this), ...)
est une alternativeoù ils ne sont pas en concurrence avec les références
boost::optional<T&>
boost::optional<T&>
Pour rappel, c'est presque toujours tort d'écrire une fonction (qui n'est pas un constructeur, ou une fonction de membre, par exemple, prend possession) qui accepte un pointeur intelligent, sauf si elle à son tour le transmettre à un constructeur (par exemple, c'est correct pour std::async
parce que du point de vue sémantique, c'est près d'être un appel à l' std::thread
constructeur). Si c'est synchrone, pas besoin de pointeur intelligent.
Pour rappel, voici un extrait qui illustre plusieurs des utilisations ci-dessus. Nous sommes à l'écrit et à l'aide d'une classe qui applique un foncteur à chaque élément d'un std::vector<int>
lors de l'écriture sur la sortie.
class apply_and_log {
public:
// C++03 exception: it's acceptable to pass by pointer to const
// to avoid apply_and_log(std::cout, std::vector<int>())
// notice that our pointer would be left dangling after call to constructor
// this still adds a requirement on the caller that v != 0 or that we throw on 0
apply_and_log(std::ostream& os, std::vector<int> const* v)
: log(&os)
, data(v)
{}
// C++0x alternative
// also usable for C++03 with requirement on v
apply_and_log(std::ostream& os, std::vector<int> const& v)
: log(&os)
, data(&v)
{}
// now apply_and_log(std::cout, std::vector<int> {}) is invalid in C++0x
// && is also acceptable instead of const&&
apply_and_log(std::ostream& os, std::vector<int> const&&) = delete;
// Notice that without effort copy (also move), assignment and destruction
// are correct.
// Class invariants: member pointers are never 0.
// Requirements on construction: the passed stream and vector must outlive *this
typedef std::function<void(std::vector<int> const&)> callback_type;
// optional callback
// alternative: boost::optional<callback_type&>
void
do_work(callback_type* callback)
{
// for convenience
auto& v = *data;
// using raw pointers as iterators
int* begin = &v[0];
int* end = begin + v.size();
// ...
if(callback) {
callback(v);
}
}
private:
// association: we use a pointer
// notice that the type is polymorphic and non-copyable,
// so composition is not a reasonable option
std::ostream* log;
// association: we use a pointer to const
// contrived example for the constructors
std::vector<int> const* data;
};
L'utilisation de pointeurs intelligents est toujours recommandée car ils documentent clairement la propriété.
Ce qui nous manque vraiment, cependant, est un pointeur intelligent "vierge", qui n'implique aucune notion de propriété.
template <typename T>
class ptr // thanks to Martinho for the name suggestion :)
{
public:
ptr(T* p): _p(p) {}
template <typename U> ptr(U* p): _p(p) {}
template <typename SP> ptr(SP const& sp): _p(sp.get()) {}
T& operator*() const { assert(_p); return *_p; }
T* operator->() const { assert(_p); return _p; }
private:
T* _p;
}; // class ptr<T>
C'est, en effet, la version la plus simple de tout pointeur intelligent qui puisse exister: un type qui documente qu'il ne possède pas la ressource qu'il pointe également.
Dans un cas, le comptage de référence (utilisé par les shared_ptr en particulier) se décomposent est lorsque vous créez un cycle sur les pointeurs (par exemple, Un des points à B, de B les points pour Un, ou A->B->C->A, ou etc). Dans ce cas, aucun de ces objets ne sera jamais libérée automatiquement, parce qu'ils sont tous en gardant des uns et des autres comptes de référence supérieure à zéro.
Pour cette raison, chaque fois que je suis en créant des objets qui ont une relation parent-enfant (par exemple, un arbre d'objets), je vais utiliser shared_ptrs dans les objets parents à tenir leur enfant objets, mais si l'enfant objets ont besoin d'un pointeur de retour à leur parent, je vais utiliser un simple C/C++ pointeur pour que.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.