【发布时间】:2016-05-16 03:38:25
【问题描述】:
我有以下类,它包含一个名为 Index 的数据结构,它的计算成本很高。 所以我将索引缓存到磁盘并再次读取它。模板类型 T 的索引元素 id 可以与多种原始数据类型一起使用。
但我也想使用类型为 std::string 的 id。我为一般情况编写了序列化/反序列化代码,并测试了它是否适用于普通的 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>;
【问题讨论】:
-
没有。就是不行。不要这样做。
-
如果您必须使用 fread 而不是可以写入 std::string 的 iostreams 函数,然后创建一个 char 缓冲区 [4096] (或您喜欢的任何最大大小),fread 进去,然后构造一个带有
string s(buffer, indexTableSize)的字符串 -
您原则上可以使用自定义分配器对其进行测试,该分配器在被要求分配时立即抛出。在循环中创建逐渐变大的字符串,并捕获异常。在实践中,虽然查找所需的所有编译器可能更容易,但它可能几乎总是 22 个字符。
-
永远不要在现实生活中编写这样的代码。它可以正常工作六个月,然后在 RHEL 6、Visual Studio 2018 或 32 位或 128 位系统上编译时出现惊人的崩溃。
-
在 C++/CLI .NET 上也可能会失败,因为我认为 std::string 可能是某种共享 CLR 对象,以便更容易传递给其他 .NET 软件。
标签: c++ string serialization stl stdstring