简体   繁体   中英

How to write a copy constructor for a class with std::vector<unsigned char*> member variable

Is simple assignement of the member vectors enough?

class WidgetNames
{
    WidgetNames(int sz)
    {
        unsigned char* c = new unsigned char[ sz ];
        memset(c,0,sz);
        m_names.push_back( c );
            m_len.push_back(sz);
    }
    ~WidgetNames()
    {
        for ( size_t i = 0 ; i < m_names.size() ; ++i )
        {
            if( m_names[i] != NULL )
            {
                delete [] m_names[i];
            }
        }   
    }
    WidgetNames(const WidgetNames &other)
    {
        m_names = other.m_names;
    }
    std::vector<unsigned char*> m_names;
    std::vector<int> m_len;
};

I am getting a crach in my destructor which makes me suspicious that the copy constructor might be the culprit. Or may be my problem is elsewhere

EDIT
Added length of the buffers. This is not the complete class def I just wanted to provide sufficient info to solicit help.
No, I can't use std:: string because I want to share the member vector with ac functions that can write to the buffers

As you don't store the size of the char array you allocate there isn't any way to do the copy constructor

Try using:

std::vector< std::vector< unsigned char > > m_names;

Your constructor would then look like this.

WidgetNames(int sz)
{
    std::vector< unsigned char > c;
    c.resize( sz );
    m_names.push_back( c );
}

instead. Or, even easier, as it looks like strings you are storing just use

std::vector< std::string > m_names;

Edit : The above not withstanding you would need to do the following in your copy constructor.

WidgetNames(const WidgetNames &other)
{
    int i = 0;
    while( i < m_names.size() )
    {
        delete[] m_names[i];
        i++;
    }

    m_names.resize( other.m_names.size() );
    m_len.resize( other.m_len.size() );
    i = 0;
    while( i < m_names.size() )
    {
        m_len[i]   = other.m_len[i];
        m_names[i] = new unsigned char[m_len[i]] );
        memcpy( m_names[i], other.m_names[i], m_len[i] );
        i++;
    }
}

You REALLY are massively better off using one of my original suggestions instead though. Far less open to errors.

Your vector contains pointers to heap memory. Suppose you do widgetNamesA=widgetNamesB , and one of them goes out of scope. The destructor is invoked, and the memory is deleted. Since the other object pointed to the same addresses, it now points to garbage and any access will produce a crash.

You'd be better off using std::string() like the other answers suggest.

EDIT : If you can't use std::string, then do something like this:

WidgetNames(const WidgetNames &other){
   //Release owned memory
   for(int i=0; i<m_names.size(); i++ ){
      delete m_names[i];
   }
   m_names.clear();
   //Allocate new memory and copy right side's contents
   for(int i=0; i<other.m_names.size(); i++ ){
      m_names.push_back( new unsigned char[other.m_len[i]] );
      memcpy( m_names[i], other.m_names[i], other.m_len[i] );
   }
}

If you use smart pointers (like std::tr1::shared_ptr ), you can forget about delete .

Then standard library vector is indeed copiable via simple assignment. Unfortunately, a unsigned char* is not, and the vector doesn't know that. Since you are manually handling the pointers construction and destruction, that means you have to manually handle the copy too.

Better practice would be to use an vector of std::string (or maybe std::basic_string), so that the construction/copy/move/destruction is all handled automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM