2013-05-23 7 views
15

std::vector è un contenitore instabile, ovvero ridimensionando il vettore, gli iteratori potrebbero essere invalidati. Al contrario, std::list o boost::container::stable_vector sono contenitori stabili che mantengono validi gli iteratori fino alla rimozione dell'elemento corrispondente.Come verificare se un contenitore è stabile

C'è un modo per verificare se un determinato contenitore è stabile? Per esempio, se ho qualcosa come

template<template <typename A, typename B=std::allocator<A> > class T=std::list> 
class Foo 
{ 
} 

È possibile consentire solo per contenitori stabili e vietare quelli instabili?

+1

Interessante domanda. –

+0

Ecco perché abbiamo bisogno di concetti! (Penso) –

+0

@MarkGarcia: Ecco perché abbiamo bisogno * di assiomi *, infatti. Concetti senza assiomi non possono catturare tali requisiti semantici. Non sono sicuro che li avremo presto, però ... –

risposta

6

Non penso che ci sia qualcosa di disponibile che fornisca tali informazioni, ma potresti scrivere il tuo tratto personale. Tuttavia, è necessario specializzarlo per ogni contenitore stabile che può essere utilizzato, che forse non è un'opzione.

#include <boost/container/vector.hpp> 

#include <iostream> 
#include <type_traits> 
#include <list> 
#include <vector> 

template <template <typename...> class Container> 
struct is_stable 
    : std::false_type 
{}; 

template <> 
struct is_stable<std::list> 
    : std::true_type 
{}; 

template <> 
struct is_stable<boost::container::stable_vector> 
    : std::true_type 
{}; 

template<template <typename...> class Container = std::list> 
class Foo 
{ 
    static_assert(is_stable<Container>::value, "Container must be stable"); 
}; 

int main() 
{ 
    Foo<std::list> f1; // ok 
    Foo<std::vector> f2; // compiler error 
} 

Non penso ci sia un modo per rilevare automaticamente che un container è stabile, senza ricorrere alla specializzazione manuale.


Solo per divertimento, ho provato a scrivere ciò che il concetto/assioma per la stabilità sarebbe simile (concepts e axioms sono un'estensione al linguaggio che erano considered for inclusion in C++11):

concept StableGroup<typename C, typename Op> 
    : Container<C> 
{ 
    void operator()(Op, C, C::value_type); 

    axiom Stability(C c, Op op, C::size_type index, C::value_type val) 
    { 
     if (index <= c.size()) 
     { 
      auto it = std::advance(c.begin(), index); 
      op(c, val); 
      return it; 
     } 
     <-> 
     if (index <= c.size()) 
     { 
      op(c, val); 
      return std::advance(c.begin(), index); 
     } 
    } 
} 

Se pensi questo correttamente cattura il requisito che ogni iteratore sul contenitore originale sia equivalente all'iteratore corrispondente sul contenitore modificato. Non è sicuro che sia molto utile, ma inventare questi assiomi è un esercizio interessante :)!

+1

Questo è assolutamente corretto: stabile/instabile è un'idea molto astratta. Un vettore può facilmente non invalidare i suoi iteratori: potrebbe non ridimensionare l'array quando pensi che lo faccia o anche se lo fa, potrebbe essere in grado di estendere il blocco di memoria esistente che usa (a seconda del compilatore ecc.). Se scrivo il mio contenitore, potrebbe facilmente riallocare la memoria in maniera non deterministica. – cristicbz

+0

Questo tratto si interrompe se non si include l'intestazione con 'boost :: stable_vector', ad esempio. Per essere generalmente utilizzabili, devi anche inoltrare per dichiarare tutte le classi per le quali stai specializzando. – jrok

+0

@jrok: Sì, questo è il motivo per cui questa soluzione è lungi dall'essere ideale. Idealmente, sarebbe responsabilità delle librerie di container specializzare il tratto, ma ovviamente non è un'opzione. Un'altra possibilità è quella di lasciare il carattere non specializzato (a parte i contenitori più comuni) e indicare agli utenti di 'Foo' che, se desiderano utilizzare un altro contenitore, devono specializzare il tratto: il' static_assert' attirerà la loro attenzione su questa parte di la documentazione, che dovrebbe rendere molto chiaro che il contenitore deve essere stabile. Ancora non molto comodo, però. –