Criar biblioteca para substituir o operador * () do iterador - ponteiro dangling de risco

Estou tentando criar o meu próprioboost::adaptors::transformed.

Aqui está o relacionadocódigo de reforço.

Aqui está o seu uso (modificado deuma resposta SO por LogicStuff): -

C funcPointer(B& b){ 
    //"funcPointer" is function convert from "B" to "C"
    return instance-of-C
}

MyArray<B> test;  //<-- any type, must already have begin() & end()

for(C c : test | boost::adaptor::transformed(funcPointer)) {
    //... something ....
}

O resultado será o mesmo que: -

for(auto b : test) {
    C c = funcPointer(b);
    //... something ...
}
Minha tentativa

eu crieiCollectAdapter que visam trabalhar comoboost::adaptor::transformed.
Funciona bem nos casos mais comuns.

Aqui está odemonstração ecópia de segurança. (igual ao código abaixo)

A parte problemática éCollectAdapter - o núcleo da minha biblioteca.
Não sei se devo armazenar em cache ocollection_ por ponteiro oupor valor.

CollectAdapter encapsula subjacentecollection_ (por exemplo, ponteiro parastd::vector<>): -

template<class COLLECTION,class ADAPTER>class CollectAdapter{
    using CollectAdapterT=CollectAdapter<COLLECTION,ADAPTER>;
    COLLECTION* collection_;    //<---- #1  problem? should cache by value?
    ADAPTER adapter_;           //<---- = func1 (or func2)
    public: CollectAdapter(COLLECTION& collection,ADAPTER adapter){
        collection_=&collection;
        adapter_=adapter;
    }
    public: auto begin(){
        return IteratorAdapter<
            decltype(std::declval<COLLECTION>().begin()),
            decltype(adapter_)>
            (collection_->begin(),adapter_);
    }
    public: auto end(){ ..... }
};

IteratorAdapter (usado acima) encapsula o iterador subjacente, altera o comportamento deoperator* : -

template<class ITERATORT,class ADAPTER>class IteratorAdapter : public ITERATORT {
    ADAPTER adapter_;
    public: IteratorAdapter(ITERATORT underlying,ADAPTER adapter) :
        ITERATORT(underlying),
        adapter_(adapter)
    {   }
    public: auto operator*(){
        return adapter_(ITERATORT::operator*());
    }
};

CollectAdapterWidget (usado abaixo) é apenas uma classe auxiliar para construirCollectAdapter-instância.

Pode ser usado como: -

int func1(int i){   return i+10;   }
int main(){
    std::vector<int> test; test.push_back(5);
    for(auto b:CollectAdapterWidget::createAdapter(test,func1)){
        //^ create "CollectAdapter<std::vector<int>,func1>" instance
         //here, b=5+10=15
    }
}  
Problema

O código acima funciona bem na maioria dos casos, exceto quandoCOLLECTION é um objeto temporário.

Mais especificamente, o ponteiro pendente ocorre potencialmente quando eu crioadaptador de adaptador de adaptador ....

int func1(int i){   return i+10;    }
int func2(int i){   return i+100;   }
template<class T> auto utilityAdapter(const T& t){
    auto adapter1=CollectAdapterWidget::createAdapter(t,func1);
    auto adapter12=CollectAdapterWidget::createAdapter(adapter1,func2);
    //"adapter12.collection_" point to "adapter1"
    return adapter12;
    //end of scope, "adapter1" is deleted
    //"adapter12.collection_" will be dangling pointer
}
int main(){
    std::vector<int> test;
    test.push_back(5);
    for(auto b:utilityAdapter(test)){
        std::cout<< b<<std::endl;   //should 5+10+100 = 115
    }
}

Isso causará erro no tempo de execução. Aqui estáa demonstração do ponteiro oscilante.

No uso real, se a interface for mais impressionante, por exemplo, usar| operador, o erro será ainda mais difícil de ser detectado: -

//inside "utilityAdapter(t)"
return t|func1;        //OK!
return t|func1|func2;  //dangling pointer
Pergunta, questão

Como melhorar minha biblioteca para corrigir esse erro, mantendodesempenho & robustez & keepablilty perto do mesmo nível?

Em outras palavras, como armazenar em cache dados ou ponteiro deCOLLECTION (Isso pode seradaptador ouestrutura de dados real) elegantemente?

Como alternativa, se for mais fácil responder codificando do zero (do que modificando meu código), faça isso. :)

Minhas soluções alternativas

O código atual armazena em cachepor ponteiro.
A principal idéia das soluções alternativas é armazenar em cachepor valor em vez de.

Solução alternativa 1 (sempre "por valor")

Deixeiadaptador armazenar em cache ovalor doCOLLECTION.
Aqui está a principal mudança: -

COLLECTION collection_;    //<------ #1 
//changed from   .... COLLECTION* collection_;

Desvantagem:-

Estrutura de dados completa (por exemplo,std::vector) serão copiados com valor - desperdice recursos.
(quando usado parastd::vector diretamente)Solução 2 (duas versões da biblioteca, melhor?)

Vou criar 2 versões da biblioteca -AdapterValue eAdapterPointer.
Eu tenho que criar classes relacionadas (Widget,AdapterIterator, etc) também.

AdapterValue - por valor. (desenhado parautilityAdapter())AdapterPointer - por ponteiro. (desenhado parastd::vector)

Desvantagem:-

Código duplicado muito = baixa manutençãoOs usuários (codificadores) devem estar muito conscientes sobre qual escolher = baixa robustezSolução alternativa 3 (tipo de detecção)

Posso usar a especialização de modelos que faz isso: -

If( COLLECTION is an "CollectAdapter" ){ by value }  
Else{ by pointer }    

Desvantagem:-

Não coopere bem entre muitas classes de adaptadores.
Eles têm que se reconhecer:reconhecido = deve armazenar em cachepor valor.

Desculpe por post muito longo.

questionAnswers(1)

yourAnswerToTheQuestion