简体   繁体   中英

memory corrupted using std::vector in constructor

Given an array of strings, I am writing a class to separated them into different groups according to their length, ie the ones of same length goes to the same group. The number of groups and the size of each group are unknown.

My idea is following: I use a private data member std::vector<std::vector<std::int> > m_groups , with the intention that the outer vector maintains the groups, and the inner vector tracks all the indices of strings belong to one group.

The problem is, once I push strings into the vector, some of my data members are corrupted. Could anyone please have a look?

Here is the simplified code:

class A {

public:
    A(std::string words[], int num, int c1[], int m, int c2[], int n);
    ~A();

    void print_state();

private:

    int *m_var; 
    int m_Nvar;

    std::vector<std::vector<std::int> > m_doms;
    std::vector<std::vector<std::int> > m_groups;
    std::vector<std::string> > m_words;

    int *m_cst1;
    int *m_cst2;
    int m_Ncst;
};

in the constructor: A::print_cst2() { for (int c = 0; c < m_Ncst; c++) { printf("%d ", m_cst2[4*c]); printf("%d ", m_cst2[4*c+1]); printf("%d ", m_cst2[4*c+2]); printf("%d ", m_cst2[4*c+3]); } }

A::A(std::string words[], int num,
    int c1[], int m, int c2[], int n) {

    ...
    m_cst1 = new int[m/2];
    m_cst2 = new int[n/4];
    m_Ncst = n/4;
    m_Nvar = m/2;

    for (int i = 0; i < n; i+=4)
    {
        m_cst2[i] = c2[i];
        m_cst2[i+1] = c2[i+1];
        m_cst2[i+2] = c2[i+2];
        m_cst2[i+3] = c2[i+3];
    }

    print_cst2();  // (1) we print the m_cst2 
    // we are only interested, the words of length smaller than m_max_len
    // put m_max_len number of empty vectors (groups) in the group vector
    for (int i = 0; i < m_max_len; i++)
    {   
        m_groups.push_back(std::vector<int>());
    }   
    print_cst2();  // (2) we print the m_cst2 again 

    // go through every words and copy words of interest to m_words
    // push the index of the word to the group it belongs to (by its length)
    for (int i = 0, k = 0; i < num; i++, k++)
    {   
        int len = words[i].length();
        if (len > m_max_len)
            continue;
        m_words.push_back(words[i]);
        m_groups[len].push_back(k);
    }

    // you can ignore this part: link the group to another structure
    for (int i = 0; i < m_Nvar; i++)
    {
         m_doms.push_back(m_groups[m_cst1[i]]);
    }

    ...
}

...

I compiled the code and run. The data in the end of array m_cst2 gets corrupted. This seems connected to the use of std::vector . User comingstorm provided an interesting clue : the outer std::vector stores an array of fixed-size std::vector<int> datastructures in its heap allocation. Is that the answer? Not sure though. So, post this and ask for suggestions.

PS: if you have a better idea to do this task, please do tell me ... if you need more information, please post.

I appreciate your time.

Some improvements below. In particular you had an off by 1 index error and the incrementation of k was incorrect:

CwordSolver::CwordSolver(std::string words[], int num,
int c1[], int m, int c2[], int n) {

    ...

    // we are only interested, the words of length smaller than m_max_len
    m_groups.resize(0);
    m_groups.resize(m_max_len, std::vector<int>());

    // go through every words and copy words of interest to m_words
    // push the index of the word to the group it belongs to (by its length)
    int k = 0;    // the index in m_words
    for (int i = 0; i < num; i++)
    {   
        int len = words[i].length();
        if (len >= m_max_len)
            continue;
        m_words.push_back(words[i]);
        m_groups[len].push_back(k);
        k++;
    }

    ...
}

If the code you posted is the actual code you're using, then this will corrupt memory.

Assume n is 4.

m_cst2 = new int[n/4];  // so you have room for 1 item
m_Ncst = n/4;
m_Nvar = m/2;

for (int i = 0; i < n; i+=4)
{
    m_cst2[i] = c2[i];      // valid
    m_cst2[i+1] = c2[i+1];  // memory overwrite
    m_cst2[i+2] = c2[i+2];  // memory overwrite
    m_cst2[i+3] = c2[i+3];  // memory overwrite
}

There is no need to go further. The value of n is 4, and clearly you are going to go out-of-bounds in m_cst2 when you write to m_cst2[1], m_cst2[2] , etc. as the only valid entry is m_cst2[0] .

So your memory corruption probably has nothing to do with std::vector (it is very difficult to mess up a vector of objects), and it more than likely has to do with the code above.

Also, you should use std::vector instead of new[]/delete[] in your code. If you're going to use vector for one thing, why not take advantage of it wherever and whenever you can?

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