62 votes

Est-ce une bonne pratique d’utiliser std :: vector en tant que tampon simple?

J'ai une application qui effectue un traitement sur certaines images.

Étant donné que je sais que la largeur/hauteur/format etc. (Je le fais), et de la pensée juste sur la définition d'une mémoire tampon pour stocker les données de pixel:

Alors, plutôt que d'utiliser new et delete [] sur unsigned char* et le maintien d'une note séparée de la taille de la mémoire tampon, je pense que je vais simplifier les choses à l'aide d'un std::vector.

Donc, je voudrais déclarer ma classe à quelque chose comme ceci:

#include <vector>

class MyClass
{
    // ... etc. ...

public:
    virtual void OnImageReceived(unsigned char *pPixels, 
        unsigned int uPixelCount);

private:
    std::vector<unsigned char> m_pImageBuffer;    // buffer for 8-bit pixels

    // ... etc. ...
};

Puis, quand j'ai reçu une nouvelle image (de certains de taille variable mais ne vous inquiétez pas à propos de ces détails ici), je peux juste redimensionner le vecteur (si nécessaire) et de copier les pixels:

void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
    // called when a new image is available
    if (m_pImageBuffer.size() != uPixelCount)
    {
        // resize image buffer
        m_pImageBuffer.reserve(uPixelCount);
        m_pImageBuffer.resize(uPixelCount, 0);
    }

    // copy frame to local buffer
    memcpy_s(&m_pImageBuffer[0], m_pImageBuffer.size(), pPixels, uPixelCount);

    // ... process image etc. ...
}

Cela semble bien pour moi, et j'aime le fait que je n'ai pas à vous soucier de la gestion de la mémoire, mais il soulève quelques questions:

  1. Est-ce une demande valable de std::vector ou un récipient approprié?
  2. Suis-je en train de faire la bonne chose en terme de performance en appelant reserve et resize?
  3. Il va toujours être le cas que la mémoire sous-jacente est consécutive afin que je puisse utiliser memcpy_s comme le montre?

Tout commentaire supplémentaire, des critiques ou des conseils seraient les bienvenus.

45voto

Sneftel Points 10929
  1. Bien sûr, cela marchera très bien. La seule chose dont vous devez vous préoccuper est de s'assurer que le tampon est correctement aligné, si votre classe repose sur un particulier de l'alignement; dans ce cas, vous souhaiterez peut-être utiliser un vecteur du type de données elle-même (comme float).
  2. Non, la réserve n'est pas nécessaire ici; redimensionner automatiquement à renforcer sa capacité en tant que de besoin, exactement de la même manière.
  3. Avant le C++03, techniquement pas (mais dans la pratique, oui). Depuis C++03, oui.

D'ailleurs, même si, memcpy_s n'est pas le idiomatiques approche ici. Utiliser std::copy à la place. Gardez à l'esprit qu'un pointeur est un itérateur.

26voto

mfontanini Points 14036

Outre les réponses mentionnées, je vous recommanderais d'utiliser std::vector::assign plutôt que std::vector::resize et memcpy :

 void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
    m_pImageBuffer.assign(pPixels, pPixels + uPixelCount);
}
 

Cela redimensionner si nécessaire, et vous serait d' éviter les inutiles 0 initialisation du tampon causé par std::vector::resize .

17voto

John Dibling Points 56814

À l'aide d'un vector dans ce cas, est très bien. En C++, le stockage est assuré d'être contigious.

Je ne voudrais pas les deux resize et reserve, et je ne voudrais memcpy copier les données dans des. Au lieu de cela, tout ce que vous devez faire est de reserve pour vous assurer de ne pas avoir à réaffecter à de nombreuses reprises, puis effacer l' vector l'aide clear. Si vous resize, il passera à travers et définir les valeurs de chaque élément à leurs valeurs par défaut -- c'est unnecesarry ici parce que vous êtes juste de le remplacer de toute façon.

Lorsque vous êtes prêt à copier les données, ne pas utiliser memcpy. Utiliser copy en conjonction avec d' back_inserter dans un vide vector:

std::copy (pPixels, pPixels + uPixelCount, std::back_inserter(m_pImageBuffer));

Je considère ceci comme un idiome à être beaucoup plus proche de canonique de l' memcpy méthode que vous employez. Il y a peut être plus rapide ou plus efficace des méthodes, mais sauf si vous pouvez prouver que c'est un goulot d'étranglement dans votre code (ce qui ne sera probablement pas; vous aurez beaucoup plus de poisson à frire ailleurs) je m'en tiendrais à idiomatiques méthodes et de laisser le prématuré micro-optimisations pour quelqu'un d'autre.

4voto

Ivan Ishchenko Points 1074

std :: vector a été fabriqué pour être utilisé dans de tels cas. Donc oui.

  1. Oui, ça l'est.

  2. reserve n'est pas nécessaire dans votre cas.

  3. Oui, il sera.

2voto

Dieter Lücking Points 10938

En outre, pour garantir un minimum de mémoire allouée:

 void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
    m_pImageBuffer.swap(std::vector<unsigned char>(
         pPixels, pPixels + uPixelCount));
    // ... process image etc. ...
}
 

vector :: assign ne change pas la quantité de mémoire allouée, si la capacité est plus grande que la quantité nécessaire:

Effets: effacer (begin (), end ()); insert (begin (), first, last);

Prograide.com

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.

Powered by:

X