简体   繁体   English

std :: vector :: resize导致模板类崩溃

[英]std::vector::resize results in a crash in a template class

Here's the code : The place where it crashed is marked with a comment( //////crash ). 这是代码:崩溃的地方标有comment( //////crash )。 I don't know what results in the problem. 我不知道是什么导致了问题。 在此处输入图片说明

After I print the size of data got from file,It shows ' 1 ' means that the array should only contains 1 element. 在我打印了从文件中获得的数据大小后,它显示为“ 1 ”表示该数组应只包含1个元素。 So it seems that there's no 'bad_allocate error' ... Could you guys help me ? 看来没有“ bad_allocate错误”……你们能帮我吗? I would appreciate your kindly help very much. 非常感谢您的帮助。 :) :)

#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<type_traits>
using namespace std;

bool read_int(int& val,FILE*& fp)
{
    if(fp == nullptr)
        return false;
    fread(&val,sizeof(int),1,fp);
    return true;
}

bool write_int(int val,FILE*& fp)
{
    if(fp == nullptr)
    {
        return false;
    }
    fwrite(&val,sizeof(int),1,fp);
    return true;
}


struct SANOBJ
{
    char path[128];
    char nickname[40];
    SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
    {
        if(_p == nullptr || _n == nullptr)
            *this = {};
        int m = strlen(_p),n = strlen(_n);
        if(m < 128) strcpy(path,_p);
        if(n < 40) strcpy(nickname,_n);
    }
    ~SANOBJ(){}
    SANOBJ(const SANOBJ& other)
    {
        memcpy(path,other.path,sizeof(char) * 128);
        memcpy(nickname,other.nickname,sizeof(char) * 40);
    }
    bool operator < (const SANOBJ& other) const
    {
        return string(path) < string(other.path);
    }
    bool operator == (const SANOBJ& other) const
    {
        return (strcmp(other.path,path) == 0);
    }
};

template <typename source_type>     //the 'source_type' type need to have the member 'int m_index'
class FrameQueue
{
public:
    FrameQueue()    //fill the 1st frame automatically
    {
        source_type new_node;
        new_node.m_index = 0;
        m_data.push_back(new_node);
    }
    FrameQueue(const FrameQueue& other)
    {
        m_data = other.m_data;
    }

    bool AddFrame(const source_type& other) // keeps an ascending order
    {
        int index = _binary_search(other);
        if(index != -1)
        {
            return false;
        }
        m_data.insert(std::upper_bound(m_data.begin(),m_data.end(),other,
                                    [](const source_type& a,const source_type& b)->bool const{return a.m_index < b.m_index;}
                                    ),other);
        return true;
    }

    bool DeleteFrameByElemIndex(int elemIndex)  //delete frame according to the index of frame in the queue
    {
        if(elemIndex < 0)
            return false;
        if(elemIndex >= m_data.size())
            return false;
        typename std::vector<source_type>::iterator it ;
        it = m_data.begin() + elemIndex;
        it = m_data.erase(it);
        return true;
    }

    bool DeleteFrameByFrameIndex(int frameIndex)
    {
        source_type node = {};
        node.m_index = frameIndex;
        int index = _binary_search(node);
        if(index == -1)
        {
            return false;
        }
        typename std::vector<source_type>::iterator it;
        it = m_data.begin() + index;
        it = m_data.erase(it);
        return true;
    }

    bool Clear()        // There would always be a single frame
    {
        source_type new_node = {};
        new_node.m_index = 0;
        m_data.clear();
        m_data.push_back(new_node);
        return true;
    }

    bool WriteFile(FILE*& fp)
    {
        if(fp == nullptr)
            return false;
        bool result = write_int(m_data.size(),fp);
        if(result == false)
            return false;
        fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
        return true;
    }

    bool ReadFile(FILE*& fp)
    {
        if(fp == nullptr)
            return false;
        int data_size;
        bool result = read_int(data_size,fp);
        if(result == false)
            return false;
        if(data_size > 0)
        {
            m_data.resize(data_size);
            fread(&(m_data[0]),sizeof(source_type),data_size,fp);
        }
        return true;
    }
private:
    int _binary_search(source_type target)
    {
        int l = 0,r = (int)m_data.size() - 1,mid;
        while(l<=r)
        {
            mid = (l + r) / 2;
            if(m_data[l].m_index == target.m_index)
            {
                return l;
            }
            if(m_data[r].m_index == target.m_index)
            {
                return r;
            }
            if(m_data[mid].m_index == target.m_index)
            {
                return mid;
            }
            if(m_data[mid].m_index > target.m_index)
            {
                r = mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
        return -1;
    }
    public:
    vector<source_type> m_data;
};

template<typename source_type>
class UniqueSource
{
public:
    UniqueSource(){}
    ~UniqueSource(){}
    bool Add(const source_type& other)//return false when insert failed,otherwise return true
    {
        if(m_map_source_to_index.find(other) == m_map_source_to_index.end())
        {
            int map_size = m_map_source_to_index.size();
            m_data.push_back(other);
            m_map_source_to_index.insert(pair<source_type,int>(other,map_size));
            m_result.push_back(map_size);
            return true;
        }
        else
        {
            m_result.push_back(m_map_source_to_index[other]);
            return true;
        }
        return false;
    }

    bool Delete(int elemIndex)  // delete the elem by elem Index,If succeed ,return true,otherwise return false
    {
        if(elemIndex < 0)
            return false;
        if(elemIndex >= m_data.size())
            return false;
        typename std::map<source_type,int>::iterator mit;
        typename std::vector<source_type>::iterator vit;
        for(mit = m_map_source_to_index.begin();mit!=m_map_source_to_index.end();++mit)
        {
            m_map_source_to_index.erase(mit);
        }
        vit = m_data.begin() + elemIndex;
        m_data.erase(vit);
        return true;
    }

    bool Clear()
    {
        m_map_source_to_index.clear();
        m_data.clear();
        m_result.clear();
        return true;
    }

    bool WriteFile(FILE*& fp)
    {
        if(fp == nullptr)
            return false;
        bool result = write_int(m_data.size(),fp);
        if(result == false)
            return false;
        if(m_data.size() > 0)
            fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
        result = write_int(m_result.size(),fp);
        if(result == false)
            return false;
        if(m_result.size() > 0)
            fwrite(&(m_result[0]),sizeof(int),m_result.size(),fp);
        return true;
    }

    bool ReadFile(FILE*& fp)
    {
        if(fp == nullptr)
            return false;
        Clear();
        int data_size;
        read_int(data_size,fp);
        if(data_size > 0)
        {
            printf("[%d]",data_size);
            m_data.resize(data_size);   /////////////////Crash!!!!!!!!!!!!
            printf("Resize Ok\r\n");
            fread(&(m_data[0]),sizeof(source_type),data_size,fp);
        }
        read_int(data_size,fp);
        printf("[%d]",data_size);
        if(data_size > 0)
        {
            m_result.resize(data_size);
            fread(&(m_result[0]),sizeof(int),data_size,fp);
        }
        return true;
    }
//private:
    map<source_type,int> m_map_source_to_index;
    vector<source_type> m_data;
    vector<int> m_result;   //the index I want
};

int main()
{
    UniqueSource<SANOBJ> m;
    SANOBJ t = {"123","456"};
    m.Add(t);
    printf("Added\r\n");
    FILE* fp = nullptr;
    fp = fopen("test.b","wb");
    if(fp == nullptr)
    {
        printf("Failed...\r\n");
    }
    bool ret = false;
    ret = m.WriteFile(fp);
    if(ret)
    {
        printf("Writed!\r\n");
        fclose(fp);
    }
    fp = fopen("test.b","rb");
    if(fp == nullptr)
    {
        printf("Failed...\r\n");
    }
    ret = m.ReadFile(fp);
    fclose(fp);
    printf("Readed\r\n");
    for(int i=0;i<m.m_data.size();i++)
        printf("%s %s\r\n",m.m_data[i].path,m.m_data[i].nickname);
    return 0;
}

Yes. 是。 The problem is is with *this = {} 问题在于* this = {}

If I were you, I'd rewrite SANOBJ constructor like this (this is a rough code and you may need to slightly modify it if you wish) 如果您是我,我将像这样重写SANOBJ构造函数(这是一个粗略的代码,如果需要,您可能需要稍作修改)

SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
    if (( _p != nullptr ) && ((strlen(_p) < 128)))
        strcpy(path,_p);

    if (( _n != nullptr ) && ((strlen(_n) < 40)))
        strcpy(nickname,_n);
}

It'll resolve the problem. 它将解决问题。

Naturally, I don't play with *this (not this). 自然,我不玩* this(不是this)。

*this = {} default-constructs a new SANOBJ instance and then assigns it to *this . *this = {}默认构造一个新的SANOBJ实例,然后将其分配给*this This would normally be OK, but here you are calling it from the SANOBJ default constructor (making the logic being something like "to default-construct a SANOBJ , default-construct a SANOBJ and then assign its value to myself"), leading to infinite recursion and eventually a stack overflow. 通常这是可以的,但是在这里您要从SANOBJ默认构造函数调用它(使逻辑类似于“默认构造SANOBJ ,默认构造SANOBJ ,然后将其值分配给我自己”),导致无限递归并最终导致堆栈溢出。

Sidenote: The copy constructor is not needed. 旁注:不需要复制构造函数。

If you want to be sure that the member variables are empty (char path[128] and char nickname[40]) set at the beginning of the constructor something like: path[0] = '\\0'; nickname[0] = '\\0'; 如果要确保成员变量为空(char path [128]和char昵称[40]),请在构造函数的开头设置以下内容: path[0] = '\\0'; nickname[0] = '\\0'; path[0] = '\\0'; nickname[0] = '\\0'; Or use something like on constructor: 或者在构造函数上使用类似的东西:

SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
    : path(), nickname()
{

}

But don't use *this= {} 但不要使用*this= {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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