C++ 可靠地使用C++;小字符串优化,将短std::字符串从文件放入内存

C++ 可靠地使用C++;小字符串优化,将短std::字符串从文件放入内存,c++,string,serialization,stl,stdstring,C++,String,Serialization,Stl,Stdstring,我有一个类,它包含一个叫做索引的数据结构,计算起来很昂贵。 因此,我将索引缓存到磁盘并再次读取它。模板类型T的索引元素id可以与各种基本数据类型一起使用 但我也希望将id与std::string类型一起使用。我为一般情况编写了序列化/反序列化代码,并测试了它是否与普通C++字符串一起工作,如果它们足够短,它们就可以工作。小字符串优化似乎起了作用 我还编写了一个不同的实现,只是为了安全地处理较长的字符串。但是安全代码的速度要慢10倍左右,我真的很想用fread读取字符串(500毫秒的读取非常痛苦,

我有一个类,它包含一个叫做索引的数据结构,计算起来很昂贵。 因此,我将索引缓存到磁盘并再次读取它。模板类型T的索引元素id可以与各种基本数据类型一起使用

但我也希望将id与std::string类型一起使用。我为一般情况编写了序列化/反序列化代码,并测试了它是否与普通C++字符串一起工作,如果它们足够短,它们就可以工作。小字符串优化似乎起了作用

我还编写了一个不同的实现,只是为了安全地处理较长的字符串。但是安全代码的速度要慢10倍左右,我真的很想用fread读取字符串(500毫秒的读取非常痛苦,而50毫秒则非常好)

如果我知道所有标识符都比可能的最长短字符串短,那么如何可靠地使用libcpp小字符串优化?我怎样才能可靠地说出可能最长的小字符串有多长

template<typename T>
class Reader {
public:
    struct Index {
        T id;
        size_t length;
        // ... values etc
    };

    Index* index;
    size_t indexTableSize;

    void serialize(const char* fileName) {
        FILE *file = fopen(fileName, "w+b");
        if (file == NULL)
            return;

        fwrite(&indexTableSize, sizeof(size_t), 1, file);
        fwrite(index, sizeof(Index), indexTableSize, file);

        fclose(file);
    }

    void deserialize(const char* fileName) {
        FILE *file = fopen(fileName, "rb");
        if (file == NULL)
            return;

        fread(&indexTableSize, sizeof(size_t), 1, file);
        index = new Index[indexTableSize];
        fread(index, sizeof(Index), indexTableSize, file);

        fclose(file);
    }


};

// works perfectly fine
template class Reader<int32_t>;

// works perfectly fine for strings shorter than 22 bytes
template class Reader<std::string>;
模板
类读取器{
公众:
结构索引{
T-id;
尺寸与长度;
//…价值观等
};
指数*指数;
大小\u t索引大小;
无效序列化(常量字符*文件名){
FILE*FILE=fopen(文件名为“w+b”);
if(file==NULL)
返回;
fwrite(&indexTableSize,sizeof(size_t),1,file);
fwrite(index,sizeof(index),indexTableSize,file);
fclose(文件);
}
无效反序列化(常量字符*文件名){
FILE*FILE=fopen(文件名,“rb”);
if(file==NULL)
返回;
fread(&indexTableSize,sizeof(size_t),1,文件);
索引=新索引[索引大小];
fread(index,sizeof(index),indexTableSize,file);
fclose(文件);
}
};
//很好用
模板类读取器;
//对于小于22字节的字符串,它的效果非常好
模板类读取器;

std::string
不可用。并在C++中执行<代码> MyCPy < /C> >类型(它相当于<代码> f> <代码> > IND和<代码> FADAD
如果要序列化字符串,必须手动进行序列化。您必须获得字符数并编写它,然后自己编写这些字符。要将其读回,必须先读取字符串的大小,然后读取那么多字符。

std::string
不是。并在C++中执行<代码> MyCPy < /C> >类型(它相当于<代码> f> <代码> > IND和<代码> FADAD
如果要序列化字符串,必须手动进行序列化。您必须获得字符数并编写它,然后自己编写这些字符。要将其读回,您必须先读取字符串的大小,然后再读取那么多字符。

如果您希望使用类型T可靠地进行序列化/反序列化,则必须确保类型T是类型(或者更准确地说是和)

您可以使用和在模板中对此进行检查。不幸的是,对于
std::string
,这将失败

如果不是这样,您必须找到一种正确的方法来序列化/反序列化类,即写入/读取允许重构对象状态的数据(这里是字符串的长度及其内容)

三种选择:

  • 使用一个辅助模板,将T从字节数组转换为字节数组,并为您的读卡器可能使用的每种类型编写此模板的专门化
  • 使用执行此操作的成员函数。但这对于std类型是不可能的
  • 使用序列化库,例如,或

在任何情况下,我都强烈建议您不要依赖于不可移植的属性,例如短字符串的长度,特别是如果您的模板中有此代码,该模板应该使用泛型类型

如果希望使用类型T可靠地序列化/反序列化,则必须确保类型T是一个类型(或者更准确地说是一个简单的类型)

您可以使用和在模板中对此进行检查。不幸的是,对于
std::string
,这将失败

如果不是这样,您必须找到一种正确的方法来序列化/反序列化类,即写入/读取允许重构对象状态的数据(这里是字符串的长度及其内容)

三种选择:

  • 使用一个辅助模板,将T从字节数组转换为字节数组,并为您的读卡器可能使用的每种类型编写此模板的专门化
  • 使用执行此操作的成员函数。但这对于std类型是不可能的
  • 使用序列化库,例如,或

在任何情况下,我都强烈建议您不要依赖于不可移植的属性,例如短字符串的长度,特别是如果您的模板中有此代码,该模板应该使用泛型类型

不。只是不。不要这样做。如果你必须使用fread而不是可以写入std::string的iostreams函数,那么就制作一个char缓冲区[4096](或任何你喜欢的最大大小),将fread放入其中,然后用
string s(buffer,indexTableSize)构造一个字符串
原则上,您可以使用自定义分配器对其进行测试,该分配器在请求分配时立即抛出。在循环中创建逐渐增大的字符串,并捕获异常。在实践中,尽管查找所有需要的编译器可能更容易,但它几乎总是22个字符。在现实生活中,永远不要编写这样的代码。它可以正常工作六个月,然后在RHEL6、VisualStudio2018或32位或128位系统上编译时会轰然爆炸