gor*_*ill 5 c++ stl vector memory-mapped-files allocator
我正在尝试实现自定义allocator以将内存映射文件存储在std::vector. 执行的文件映射boost::iostreams::mapped_file
文件内存映射的分配器类型:
template<typename T>
class mmap_allocator
{
public:
typedef T value_type;
mmap_allocator(const std::string& filename)
: _mmfile(filename) { }
T* allocate (size_t n)
{
return reinterpret_cast<T*>(_mmfile.data());
}
void deallocate (T* p, size_t n)
{
p = nullptr;
_mmfile.close();
}
private:
boost::iostreams::mapped_file _mmfile;
};
Run Code Online (Sandbox Code Playgroud)
内存映射文件的容器,基于std::vector:
//Get file size
long GetFileSize(std::string filename)
{
FILE *p_file = NULL;
p_file = fopen(filename.c_str(),"rb");
fseek(p_file,0,SEEK_END);
int size = ftell(p_file);
fclose(p_file);
return size;
}
template<typename T>
class mm_vector : public std::vector<T, mmap_allocator<T> >
{
public:
typedef mmap_allocator<T> allocator_type;
typedef std::vector<T, allocator_type > b_vector;
mm_vector(const std::string filename) : b_vector(GetFileSize(filename)/sizeof(T), allocator_type(filename))
{
b_vector::reserve(GetFileSize(filename)/sizeof(T));
}
};
Run Code Online (Sandbox Code Playgroud)
测试代码:
int main()
{
mm_vector<int> v("test.f");//test.f - binary file contain several integers
for(auto x : v) std::cout<<x<<" ";
}
Run Code Online (Sandbox Code Playgroud)
此代码无法正常工作 - 输出始终为零。文件包含正确的内容 - 几个整数。这段代码运行良好:
boost::iostreams::mapped_file _mmfile("test.f");
int* p = (int*)(_mmfile.data());
std::cout<<p[0];
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
问题是零初始化,调用接收大小的构造函数,分配器会将向量元素初始化为元素类型的默认值(在本例中为 0)。这是标准规定的。
23.3.7.2 向量构造函数、复制和赋值 [vector.cons] § 23.3.7.2 789
explicit vector(size_type n, const Allocator& = Allocator());
Run Code Online (Sandbox Code Playgroud)
-Effects:使用指定的分配器构造一个带有 n 个默认插入元素的向量。
- 要求:T 应该是 DefaultInsertable 到 *this。
- 复杂性:n 中的线性。
在我的情况下,使用的文件也填充了 0。在 GCC 4.9.0 中测试。有逻辑,因为 mapping_file 的默认 mapmode 是readwrite.
在示例代码中,我在分配发生时(在自定义分配器中)添加了映射内存内容的打印,在向量的构造和 main 中的现有打印中。第一次打印输出文件的正确数据,第二次输出归零版本。
#include <vector>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <boost/iostreams/device/mapped_file.hpp>
template <typename T>
class mmap_allocator {
public:
typedef T value_type;
mmap_allocator(const std::string& filename) : _mmfile(filename) {}
T* allocate(size_t n) {
std::cout << "OUTPUT 1:" << std::endl;
auto v = reinterpret_cast<T*>(_mmfile.data());
for (unsigned long idx = 0; idx < _mmfile.size()/sizeof(int); idx++)
std::cout << v[idx] << " ";
return reinterpret_cast<T*>(_mmfile.data());
}
void deallocate(T* p, size_t n) {
p = nullptr;
_mmfile.close();
}
private:
boost::iostreams::mapped_file _mmfile;
};
// Get file size
long GetFileSize(std::string filename) {
FILE* p_file = NULL;
p_file = fopen(filename.c_str(), "rb");
fseek(p_file, 0, SEEK_END);
int size = ftell(p_file);
fclose(p_file);
return size;
}
template <typename T>
class mm_vector : public std::vector<T, mmap_allocator<T>> {
public:
typedef mmap_allocator<T> allocator_type;
typedef std::vector<T, allocator_type> b_vector;
mm_vector(const std::string filename)
: b_vector(GetFileSize(filename) / sizeof(T),
allocator_type(filename)) {
std::cout << std::endl << std::endl << "OUTPUT 2:" << std::endl;
for (auto x : *this)
std::cout << x << " ";
b_vector::reserve(GetFileSize(filename) / sizeof(T));
}
};
int main(int argc, char* argv[]) {
std::chrono::system_clock::time_point begin_time =
std::chrono::system_clock::now();
mm_vector<int> v("H:\\save.txt");
std::cout << std::endl << std::endl << "OUTPUT 2:" << std::endl;
for (auto x : v)
std::cout << x << " ";
std::chrono::system_clock::time_point end_time =
std::chrono::system_clock::now();
long long elapsed_miliseconds =
std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - begin_time).count();
std::cout << "Duration (min:seg:mili): " << std::setw(2)
<< std::setfill('0') << (elapsed_miliseconds / 60000) << ":"
<< std::setw(2) << std::setfill('0')
<< ((elapsed_miliseconds / 1000) % 60) << ":" << std::setw(2)
<< std::setfill('0') << (elapsed_miliseconds % 1000) << std::endl;
std::cout << "Total milliseconds: " << elapsed_miliseconds << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)