Outils d'utilisateurs

Outils du Site


pointeurs_style_c

Ceci est une ancienne révision du document !


Indirections dans les fonctions

Plusieurs types d'indirections :

  • iterateurs → pour les collections
  • references → vu dans les parametres de fonctions
    • lvalue ref
    • rvalue ref
    • reference_wrapper
  • pointeurs → polymorphisme + peut etre nullptr
    • intelligent
      • unique_ptr (+ observer_ptr?)
      • shared_ptr + weak_ptr
      • autres… (boost, Qt, etc)
    • non manages
      • raw ptr
      • not_null<T>

Et bien d'autres… (old C++, future C++, libs, etc)

Comment ecrire une fonction qui prend une indirection en parametre ?

void f(...);  // quoi mettre ici ?
 
int i;
f(~i~);
 
std::unique_ptr<int> upi;
f(~pi~);
 
 
std::shared_ptr<int> spi;
f(~spi~);

Cas particulier des tableaux

Type d'element different a gerer, mais egalement type de collection.

void f(...);  // quoi mettre ici ?
 
std::vector<int> vi;
std::vector<string> vd;
std::list<int> li;

Dans certains cas, cela a un sens de pouvoir utiliser des collection d'elements de types differents (par exemple std::find fonctionne sur int ou string), dans d'autres cas non.

Idem pour les types de collections, parfois cela a un sens (par exemple std::find fonctionne sur vector et list) et d'autres cas non (std::sort fonctionne que sur std::vector)

A choisir selon l'API que l'on veut fournir.

Passer par valeur ou reference la collection

Passage dans une fonction :

void f(TYPE value);
void f(TYPE & ref);
void f(TYPE const& cref);
void f(TYPE && rref);

Avec TYPE = n'importe quel type compatible (ie copiable si par valeur). En particulier, possible que le type soit une collection. Par exemple si TYPE = std::vector<int>

void f(std::vector<int> const& cref);
 
std::vector<int> v;
f(v); // ok

Code moins reutilisable → specifique d'un type de collection et d'un type d'element.

void f(std::vector<int> const& cref);
 
std::list<int> l;
f(l); // erreur

Version generique avec template

Rappel fonction generique :

template<class T>
void f(T value);
 
template<class T>
void f(T & ref);
 
template<class T>
void f(T const& cref);
 
template<class T>
void f(T && rref);

Meme chose que precedent, mais le type est deduit pas le compilateur = fonctionne avec n'importe quel type de collection.

template<class T>
void f(T const& cref);
 
std::vector<int> v;
f(v); // ok
 
std::list<double> l;
f(l); // ok

Limitation : uniquement sur totalite de collection, pas une sous partie.

template<class T>
void f(T const& cref);
 
std::vector<int> v;
const it { std::find(begin(v), end(v), 123) };
f(...); // comment appliquer f que entre it et end(v) ?

Paire d'iterateurs

Utilise par les algos stl. Passe en parametre une paire d'iterateurs, deduit par template (genericite).

template<Iterator>
void f(Iterator first, Iterator last);
 
std::vector<int> v;
f(begin(v), end(v)); // ok
 
std::list<double> l;
f(begin(l), end(l)); // ok
 
const it { std::find(begin(v), end(v), 123) };
f(it, end(v));       // ok

Le plus generique !

Inconvenient = possible d'utiliser des iterateurs provenant de collection differentes + ecriture lourde.

template<Iterator>
void f(Iterator first, Iterator last);
 
std::vector<int> v;
std::list<double> l;
f(begin(v), end(l)); // erreur

Les views

Fondamentalement, paire d'iterateur sur une collection. Garantie que les 2 iterateurs viennent d'une meme collection. + ecriture plus simple.

Conceptuellement : semantique d'une collection, mais pas l'ownership. Ie sera manipule et vu par le code comme etant une collection. Mais ne gere pas les donnees elle meme, utilise une autre collection qui gere les donnees.

La vues peut correspondre a sous partie d'une collection, peut caster les types, et peut proposer d'autres fonctionnalites (par exemple voir un tableau 1D comme un tableau 2D).

Sous collection :

const std::vector<int> v { 1, 2, 3, 4, 5 };
const array_view<int> view (begin(v) + 1, end(v) - 1);
std::find(begin(view), end(view), 3); // view s'utilise comme un tableau contenant { 2, 3, 4 }

Cast : (danger…)

static_assert(sizeof(uint32_t) == sizeof(float));
const std::vector<uint32_t> v { 1, 2, 3, 4, 5 };
const array_view<float> view (begin(v), end(v));

Tableau 2D

array_view<int, 2> view ({2, 5}, v1}); // 2D
view[{1, 2}] = 5;                     // accès 2D

Note : specialisation string_view pour les chaines.

Note 2 : dans le C++17. A implementer soi meme.

Les indirections sur un objet

Solution 1 : faire le bourrin

Ecrire des surcharges de fonction pour chaque type de parametre possible…

f(int);
f(std::unique_ptr<int>);
f(std::shared_ptr<int>);

Pas du tout evolutif et maintainable.

pointeurs_style_c.1461683881.txt.gz · Dernière modification: 2016/04/26 17:18 par gbdivers