2009-11-11 7 views
8

Je dois envelopper un tableau alloué dynamiquement (d'un nouveau double [100] par exemple) dans std :: vector (de préférence) sans copier le tableau. Cette restriction est imposée par le fait que le tableau que je veux envelopper est mmapé à partir d'un fichier, donc faire juste du vecteur (a, a + taille) doublera l'utilisation de la mémoire.Envelopper une matrice dynamique dans un conteneur STL/Boost?

Est-ce des astuces pour le faire?

+1

Quoi qu'il en soit, vous ne serez pas ensemble des capacités de std :: vecteur (par exemple redimensionnez, probablement ne fonctionnera pas), alors peut-être qu'il serait bon d'énumérer exactement ce dont vous avez besoin de wrapper? – maxim1000

Répondre

11

Une des meilleures solutions pour c'est quelque chose comme STLSoft's array_proxy<> modèle. Malheureusement, la page doc générée à partir du code source par doxygen n'est pas une aide précieuse pour comprendre le modèle. Le code source peut effectivement être un peu mieux:

Le modèle est décrit array_proxy<> bien dans Matthew Wilson's book, Imperfect C++. La version que j'ai utilisée est une version réduite de ce qui se trouve sur le site de STLSoft, donc je n'ai pas eu besoin de retirer toute la bibliothèque. Ma version n'est pas aussi portable, mais cela rend la chose beaucoup plus simple que sur STLSoft (qui passe à travers un grand nombre de cerceaux de portabilité).

Si vous configurez une variable comme ceci:

int myArray[100]; 

array_proxy<int> myArrayProx(myArray); 

La myArrayProx variable a plusieurs des interfaces STL - begin(), end(), size(), itérateurs, etc.

Ainsi, à bien des égards, l'objet array_proxy<> se comporte comme un vecteur (si push_back() est pas là depuis le array_proxy<> ne peut se développer - il ne parvient pas elle enveloppe la mémoire du tableau, juste en quelque chose d'un peu plus près à un vecteur). Une chose très intéressante avec array_proxy<> est que si vous les utilisez en tant que type de paramètre de fonction, la fonction peut déterminer la taille du tableau transmis, ce qui n'est pas le cas des tableaux natifs. Et la taille du tableau enveloppé ne fait pas partie du type du modèle, donc il est assez flexible à utiliser.

+1

+1, semble être la meilleure solution, en particulier parce que le proxy ne devrait pas réaffecter la mémoire de sorte qu'il devrait être exempt de nombreux problèmes. –

1

Non, ce n'est pas possible à l'aide d'un std::vector.

Mais si possible, vous pouvez créer le vecteur avec cette taille, et peut mapper le fichier à cette place.

std::vector<double> v(100); 
mmapfile_double(&v[0], 100); 
1

Qu'en est-il vecteur de pointeurs qui pointent vers vos éléments de zone cartographiée (réduction de la consommation de mémoire sizeof (double *) < sizeof (double))? C'est bon pour toi? Il y a quelques inconvénients (en premier lieu, vous avez besoin de prédicats spéciaux pour le tri), mais vous pouvez également supprimer des éléments sans modifier le contenu mappé réel (ou avoir un nombre pair de tels tableaux avec un ordre d'éléments différent). tout changement aux valeurs réelles).

Il y a un problème commun de toutes les solutions avec std :: vecteur sur fichier mis en correspondance: au contenu vectoriel « nail » à la zone cartographiée. Cela ne peut pas être suivi, vous pouvez seulement regarder après vous-même pour ne pas utiliser quelque chose qui pourrait conduire à la ré-allocation du contenu vectoriel. Alors soyez prudent dans tous les cas.

2

j'ai été déterminé à accomplir la même chose. Après quelques jours de réflexion et d'essai, j'ai décidé que ça n'en valait pas la peine. J'ai fini par créer mon propre vecteur personnalisé comportés comme la seule façon de std :: vecteur mais seulement eu la fonctionnalité que je réellement besoin comme lié vérification, itérateurs etc.

Si vous désirez toujours utiliser std :: vector, je pouvais penser à l'époque était de créer un allocateur personnalisé. Je n'en ai jamais écrit mais vu que c'est le seul moyen de contrôler la gestion de la mémoire de STL, peut-être y a-t-il quelque chose à faire là-bas.

+2

Je suggère de ne pas écrire un propre conteneur. La plupart du temps, cela n'en vaut tout simplement pas la peine et entraîne de nombreux problèmes d'interopérabilité. De plus, le temps passé à déboguer des choses réinventées est une perte de temps. L'allocateur personnalisé est probablement assez facile à mettre en œuvre et une meilleure approche. – MP24

+0

Normalement, je serais d'accord, mais je pense vraiment que cela dépend de ce que vous allez en faire. La plupart des opérations "complexes" dans std :: vector ont probablement quelque chose à voir avec la gestion de la mémoire et il arrive que dans ce cas, aucune d'entre elles n'est requise. Donc, écrire une petite classe avec des vérifications de limites et un pointeur comme un itérateur ne devrait pas prendre trop de temps. Je ne peux pas commenter sur l'interopérabilité puisque je n'ai aucune connaissance de où/comment l'auteur a l'intention de l'utiliser. Mais le support de l'itérateur devrait le faire fonctionner avec les algorithmes de STL. –

+0

Alors, avez-vous un lien vers le code pour cela? – einpoklum

1

Vous pourriez aller avec array_proxy <>, ou jetez un oeil à Boost.Array. Il vous donne size(), front(), back(), at(), opérateur [], etc. Personnellement, je préfère Boost.Array puisque Boost est plus répandu de toute façon.

+0

-1, Boost.Array copie le contenu du tableau – CharlesB

9

A boost::iterator_range fournit une interface de type conteneur: bien

// Memory map an array of doubles: 
size_t number_of_doubles_to_map = 100; 
double* from_mmap = mmap_n_doubles(number_of_doubles_to_map); 

// Wrap that in an iterator_range 
typedef boost::iterator_range<double*> MappedDoubles; 
MappedDoubles mapped(from_mmap, from_mmap + number_of_doubles_to_map); 

// Use the range 
MappedDoubles::iterator b = mapped.begin(); 
MappedDoubles::iterator e = mapped.end(); 
mapped[0] = 1.1; 
double first = mapped(0); 

if (mapped.empty()){ 
    std::cout << "empty"; 
} 
else{ 
    std::cout << "We have " << mapped.size() << "elements. Here they are:\n" 
     << mapped; 
} 
+1

Meilleure réponse pour moi, car il utilise boost! – CharlesB

1

, le modèle vectoriel permet de fournir votre propre allocateur de mémoire. Je ne l'ai jamais fait moi-même mais je suppose que ce n'est pas si difficile de le faire pointer vers votre tableau, peut-être avec un nouvel opérateur de placement ... juste une supposition, j'écris plus si j'essaie et réussis.

0

Voici la solution à votre question. J'essayais ça depuis un certain temps avant de trouver une solution viable. L'inconvénient est que vous devez mettre à zéro les pointeurs après utilisation afin d'éviter de libérer la mémoire.

#include <vector> 
#include <iostream> 

template <class T> 
void wrapArrayInVector(T *sourceArray, size_t arraySize, std::vector<T, std::allocator<T> > &targetVector) { 
    typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *vectorPtr = 
    (typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *)((void *) &targetVector); 
    vectorPtr->_M_start = sourceArray; 
    vectorPtr->_M_finish = vectorPtr->_M_end_of_storage = vectorPtr->_M_start + arraySize; 
} 

template <class T> 
void releaseVectorWrapper(std::vector<T, std::allocator<T> > &targetVector) { 
    typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *vectorPtr = 
     (typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *)((void *) &targetVector); 
    vectorPtr->_M_start = vectorPtr->_M_finish = vectorPtr->_M_end_of_storage = NULL; 
} 

int main() { 

    int tests[6] = { 1, 2, 3, 6, 5, 4 }; 
    std::vector<int> targetVector; 
    wrapArrayInVector(tests, 6, targetVector); 

    std::cout << std::hex << &tests[0] << ": " << std::dec 
      << tests[1] << " " << tests[3] << " " << tests[5] << std::endl; 

    std::cout << std::hex << &targetVector[0] << ": " << std::dec 
      << targetVector[1] << " " << targetVector[3] << " " << targetVector[5] << std::endl; 

    releaseVectorWrapper(targetVector); 
} 

Sinon, vous pouvez juste faire une classe qui hérite de vecteur et les pointeurs nuls sur la destruction:

template <class T> 
class vectorWrapper : public std::vector<T> 
{ 
public: 
    vectorWrapper() { 
    this->_M_impl _M_start = this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = NULL; 
    } 

    vectorWrapper(T* sourceArray, int arraySize) 
    { 
    this->_M_impl _M_start = sourceArray; 
    this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = sourceArray + arraySize; 
    } 

    ~vectorWrapper() { 
    this->_M_impl _M_start = this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = NULL; 
    } 

    void wrapArray(T* sourceArray, int arraySize) 
    { 
    this->_M_impl _M_start = sourceArray; 
    this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = sourceArray + arraySize; 
    } 
}; 
Questions connexes