Reading and writing C++ vector to a file - c++

For some graphics work I need to read in a large amount of data as quickly as possible and would ideally like to directly read and write the data structures to disk. Basically I have a load of 3d models in various file formats which take too long to load so I want to write them out in their "prepared" format as a cache that will load much faster on subsequent runs of the program.
Is it safe to do it like this?
My worries are around directly reading into the data of the vector? I've removed error checking, hard coded 4 as the size of the int and so on so that i can give a short working example, I know it's bad code, my question really is if it is safe in c++ to read a whole array of structures directly into a vector like this? I believe it to be so, but c++ has so many traps and undefined behavour when you start going low level and dealing directly with raw memory like this.
I realise that number formats and sizes may change across platforms and compilers but this will only even be read and written by the same compiler program to cache data that may be needed on a later run of the same program.
#include <fstream>
#include <vector>
using namespace std;
struct Vertex
{
float x, y, z;
};
typedef vector<Vertex> VertexList;
int main()
{
// Create a list for testing
VertexList list;
Vertex v1 = {1.0f, 2.0f, 3.0f}; list.push_back(v1);
Vertex v2 = {2.0f, 100.0f, 3.0f}; list.push_back(v2);
Vertex v3 = {3.0f, 200.0f, 3.0f}; list.push_back(v3);
Vertex v4 = {4.0f, 300.0f, 3.0f}; list.push_back(v4);
// Write out a list to a disk file
ofstream os ("data.dat", ios::binary);
int size1 = list.size();
os.write((const char*)&size1, 4);
os.write((const char*)&list[0], size1 * sizeof(Vertex));
os.close();
// Read it back in
VertexList list2;
ifstream is("data.dat", ios::binary);
int size2;
is.read((char*)&size2, 4);
list2.resize(size2);
// Is it safe to read a whole array of structures directly into the vector?
is.read((char*)&list2[0], size2 * sizeof(Vertex));
}

As Laurynas says, std::vector is guaranteed to be contiguous, so that should work, but it is potentially non-portable.
On most systems, sizeof(Vertex) will be 12, but it's not uncommon for the struct to be padded, so that sizeof(Vertex) == 16. If you were to write the data on one system and then read that file in on another, there's no guarantee that it will work correctly.

You might be interested in the Boost.Serialization library. It knows how to save/load STL containers to/from disk, among other things. It might be overkill for your simple example, but it might become more useful if you do other types of serialization in your program.
Here's some sample code that does what you're looking for:
#include <algorithm>
#include <fstream>
#include <vector>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
using namespace std;
struct Vertex
{
float x, y, z;
};
bool operator==(const Vertex& lhs, const Vertex& rhs)
{
return lhs.x==rhs.x && lhs.y==rhs.y && lhs.z==rhs.z;
}
namespace boost { namespace serialization {
template<class Archive>
void serialize(Archive & ar, Vertex& v, const unsigned int version)
{
ar & v.x; ar & v.y; ar & v.z;
}
} }
typedef vector<Vertex> VertexList;
int main()
{
// Create a list for testing
const Vertex v[] = {
{1.0f, 2.0f, 3.0f},
{2.0f, 100.0f, 3.0f},
{3.0f, 200.0f, 3.0f},
{4.0f, 300.0f, 3.0f}
};
VertexList list(v, v + (sizeof(v) / sizeof(v[0])));
// Write out a list to a disk file
{
ofstream os("data.dat", ios::binary);
boost::archive::binary_oarchive oar(os);
oar << list;
}
// Read it back in
VertexList list2;
{
ifstream is("data.dat", ios::binary);
boost::archive::binary_iarchive iar(is);
iar >> list2;
}
// Check if vertex lists are equal
assert(list == list2);
return 0;
}
Note that I had to implement a serialize function for your Vertex in the boost::serialization namespace. This lets the serialization library know how to serialize Vertex members.
I've browsed through the boost::binary_oarchive source code and it seems that it reads/writes the raw vector array data directly from/to the stream buffer. So it should be pretty fast.

std::vector is guaranteed to be continuous in memory, so, yes.

Another alternative to explicitly reading and writing your vector<> from and to a file is to replace the underlying allocator with one that allocates memory from a memory mapped file. This would allow you to avoid an intermediate read/write related copy. However, this approach does have some overhead. Unless your file is very large it may not make sense for your particular case. Profile as usual to determine if this approach is a good fit.
There are also some caveats to this approach that are handled very well by the Boost.Interprocess library. Of particular interest to you may be its allocators and containers.

I just ran into this exact same problem.
First off, these statements are broken
os.write((const char*)&list[0], size1 * sizeof(Vertex));
is.read((char*)&list2[0], size2 * sizeof(Vertex));
There is other stuff in the Vector data structure, so this will make your new vector get filled up with garbage.
Solution:
When you are writing your vector into a file, don't worry about the size your Vertex class, just directly write the entire vector into memory.
os.write((const char*)&list, sizeof(list));
And then you can read the entire vector into memory at once
is.seekg(0,ifstream::end);
long size2 = is.tellg();
is.seekg(0,ifstream::beg);
list2.resize(size2);
is.read((char*)&list2, size2);

If this is used for caching by the same code, I don't see any problem with this. I've used this same technique on multiple systems without a problem (all Unix based). As an extra precaution, you might want to write a struct with known values at the beginning of the file, and check that it reads ok. You might also want to record the size of the struct in the file. This will save a lot of debugging time in the future if the padding ever changes.

Related

How to store / load big C++ containers

I was wondering how can I store C++ containers for efficient loading, for example how can I store very large vectors of integers. I know I can save them in a file, and make new vector out of that data
#include <fstream>
#include <vector>
int main()
{
vector<int> data = {1, 2, 3, 4, 5}; // some elements
std::ifstream file(path);
for (const auto &c : data)
file << c << " ";
return 0;
}
but if I want to save 1 gigabyte of data, loading it every time from a file takes a loooooooooong time. So is there a way to store this kind of data, for fast loading that doesn't take forever, if possible I would like to store my own classes this way as well.
std::vector is stored in a contiguous memory block.
If you want to store/load data from a vector to file you should be able to do something like this.
std::string filename{ "test.dat" };
std::vector<int> vec_source = { 1, 2, 3, 4, 5 }; // some elements
// Save to file
std::ofstream OutFile;
OutFile.open(filename, std::ofstream::out | std::ofstream::binary);
OutFile.write(reinterpret_cast<char*>(vec_source.data()), vec_source.size() * sizeof(int));
OutFile.close();
// Prepare
std::vector<int> vec_target;
vec_target.resize(vec_source.size());
// Load from file
std::ifstream InFile;
InFile.open(filename, std::ofstream::in| std::ofstream::binary);
InFile.read(reinterpret_cast<char*>(vec_target.data()), vec_target.size() * sizeof(int));
InFile.close();
See working example here:
https://wandbox.org/permlink/oQuwXxU8q230FaJC
[EDIT]
Few notes and limitations:
Note 1: If you plan to do more then just save/load the whole array. Like changing the data and storing only the changes you should consider a better method (like split the data into chunks, save each chunk separately)
Note 2: This method is correct only for containers which use contiguous memory block like std::vector, std::array and std::string. It will certainly not work for std::list or std::map
Note 3: Following interesting discussion between #DavidSchwartz and #Acorn in the comments of this post. This code example will work correctly only if the endianness of the platform is constant and same when storing and loading the data from the file. It will certainly will not work in case the platform changes its endianness across runs or if mixing platforms!.

Copy an Eigen vector to a C array?

How do I copy an Eigen vector mesh to a C array r?
double *r;
typedef Eigen::VectorXd RealVector;
Eigen::Map<RealVector>(r, 1, mesh.cols()) = mesh;
gives an assert from Eigen
DenseBase::resize() does not actually allow to resize.
The same message comes from either
Eigen::Map<RealVector>(r, mesh.cols()) = mesh;
or
Eigen::Map<RealVector>(r, mesh.cols(), 1) = mesh;
I need the values to be copied, not just mapped.
Since you did not clarify, I'm speculating three possible errors you could have made:
Either your mesh is actually a VectorXd, but then it will always have exactly one column, but potentially multiple rows, i.e., you need to write:
Eigen::VectorXd::Map(r, mesh.rows()) = mesh;
Or your mesh is a RowVectorXd (i.e., having one row and multiple columns). Then you need to write:
Eigen::RowVectorXd::Map(r, mesh.cols()) = mesh;
If mesh actually is a matrix, you need to decide how to map it to linear memory (i.e. row-major or column-major). This is also possible with Map:
Eigen::MatrixXd::Map(r, mesh.rows(), mesh.cols()) = mesh;
You don't have to copy anything actually. You can access the raw data using the .data() member function.
#include <Eigen/Core>
int main()
{
Eigen::VectorXd mesh = Eigen::VectorXd::Random(10);
double * r = mesh.data();
r[5] = 0; // writes to mesh directly
assert(mesh(5) == 0);
}
If you want to copy the data to the pointer, you have to allocate memory, perform the copy and deallocate after use.
#include <algorithm>
#include <Eigen/Core>
int main()
{
Eigen::VectorXd mesh = Eigen::VectorXd::Random(10);
double * r = new double[mesh.size()];
std::copy(mesh.data(), mesh.data() + mesh.size(), r);
assert(r[5] == mesh(5));
delete[] r;
}

Suggestions for returning memory from a class

I have a class which is supposed to keep pixel data (floats for the position, floats for the color). I'm trying to use a C++ style in data members (the data is kept in std::array<float, N> instead of plain C arrays). The class has other getters, setters and functions meant to be "helpers" to populate these fields.
Now I need to create an OpenGL vertex data buffer where I should write out
4 floats for xyzw
4 floats for rgba
2 floats for UV coords
in this order. I'm wondering how should I do this.. I tried doing
class MyVertexData {
std::array<float, 4> pos;
std::array<float, 4> rgba;
std::array<float, 2> uv;
public:
void writeData(float *ptrToMemory) {
if(ptrToMemory == nullptr)
throw std::runtime_exception("Null pointer");
std::array<float, 10> output;
output= {
pos[0], pos[1], pos[2], pos[3],
rgba[0], rgba[1], rgba[2], rgba[3],
uv[0], uv[1]
};
memcpy(memory, out.data(), 10 * sizeof(float));
}
};
// Caller code
std::vector<float[10]> buffer(4);
vertex0.writeElements(buffer[0]);
vertex1.writeElements(buffer[1]);
vertex2.writeElements(buffer[2]);
vertex3.writeElements(buffer[3]);
but this approach has two problems:
I need to trust the caller to have allocated memory to store 10 floats
No C++11+ signature, I just get a float pointer
I can't just return a std::unique_ptr since I need a contiguous memory area (buffer) where the elements are to be stored, but I also need a distinction between the different elements (that would also make the code more readable).
It would be nice to return a smart pointer or something similar whose memory I can easily "concatenate" to other elements so I can safely pass this stuff to OpenGL.
CppCoreGuidelines introduces span which is a view of contiguous element, so you may use something like:
void writeData(gsl::span<float, 10> ptrToMemory)
to express the intend.

Is it good practice to use std::vector as a simple buffer?

I have an application that is performing some processing on some images.
Given that I know the width/height/format etc. (I do), and thinking just about defining a buffer to store the pixel data:
Then, rather than using new and delete [] on an unsigned char* and keeping a separate note of the buffer size, I'm thinking of simplifying things by using a std::vector.
So I would declare my class something like this:
#include <vector>
class MyClass
{
// ... etc. ...
public:
virtual void OnImageReceived(unsigned char *pPixels,
unsigned int uPixelCount);
private:
std::vector<unsigned char> m_pImageBuffer; // buffer for 8-bit pixels
// ... etc. ...
};
Then, when I received a new image (of some variable size - but don't worry about those details here), I can just resize the vector (if necessary) and copy the pixels:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
// called when a new image is available
if (m_pImageBuffer.size() != uPixelCount)
{
// resize image buffer
m_pImageBuffer.reserve(uPixelCount);
m_pImageBuffer.resize(uPixelCount, 0);
}
// copy frame to local buffer
memcpy_s(&m_pImageBuffer[0], m_pImageBuffer.size(), pPixels, uPixelCount);
// ... process image etc. ...
}
This seems fine to me, and I like that fact that I don't have to worry about the memory management, but it raises some questions:
Is this a valid application of std::vector or is there a more suitable container?
Am I doing the right thing performance-wise by calling reserve and resize?
Will it always be the case that the underlying memory is consecutive so I can use memcpy_s as shown?
Any additional comment, criticism or advice would be very welcome.
Sure, this'll work fine. The one thing you need to worry about is ensuring that the buffer is correctly aligned, if your class relies on a particular alignment; in this case you may want to use a vector of the datatype itself (like float).
No, reserve is not necessary here; resize will automatically grow the capacity as necessary, in exactly the same way.
Before C++03, technically not (but in practice yes). Since C++03, yes.
Incidentally, though, memcpy_s isn't the idiomatic approach here. Use std::copy instead. Keep in mind that a pointer is an iterator.
Starting in C++17, std::byte is the idiomatic unit of opaquely typed storage such as you are using here. char will still work, of course, but allows unsafe usages (as char!) which byte does not.
Besides what other answers mention, I would recommend you to use std::vector::assign rather than std::vector::resize and memcpy:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
m_pImageBuffer.assign(pPixels, pPixels + uPixelCount);
}
That will resize if necessary, and you would be avoiding the unnecessary 0 initialization of the buffer caused by std::vector::resize.
Using a vector in this case is fine. In C++ the storage is guaranteed to be contigious.
I would not both resize and reserve, nor would I memcpy to copy the data in. Instead, all you need to do is reserve to make sure you don't have to reallocate many times, then clear out the vector using clear. If you resize, it will go through and set the values of every element to their defaults -- this is unnecesarry here because you're just going to overwrite it anyway.
When you're ready to copy the data in, don't use memcpy. Use copy in conjunction with back_inserter into an empty vector:
std::copy (pPixels, pPixels + uPixelCount, std::back_inserter(m_pImageBuffer));
I would consider this idiom to be much closer to canonical than the memcpy method you are employing. There might be faster or more efficient methods, but unless you can prove that this is a bottleneck in your code (which it likely won't be; you'll have much bigger fish to fry elsewhere) I would stick with idiomatic methods and leave the premature micro-optimizations to someone else.
I would avoid std::vector as a container for storing an unstructured buffer, as std::vector is profoundly slow when used as a buffer
Consider this (C++14) example (for C++11, you can used shared instead of unique ptrs, but you'll notice slight performance hit in the array example that you don't get from the vectors when running at -O3 or -O2):
#include <array>
#include <chrono>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
namespace {
std::unique_ptr<std::array<unsigned char, 4000000>> allocateWithPtr() {
return std::make_unique<std::array<unsigned char, 4000000>>();
}
std::vector<unsigned char> allocateWithVector() {
return std::vector<unsigned char>(4000000);
}
} // namespace
int main() {
auto start = std::chrono::system_clock::now();
for (long i = 0; i < 1000; i++) {
auto myBuff = allocateWithPtr();
}
auto ptr_end = std::chrono::system_clock::now();
for (long i = 0; i < 1000; i++) {
auto myBuff = allocateWithVector();
}
auto vector_end = std::chrono::system_clock::now();
std::cout << "std::unique_ptr = " << (ptr_end - start).count() / 1000.0
<< " ms." << std::endl;
std::cout << "std::vector = " << (vector_end - ptr_end).count() / 1000.0
<< " ms." << std::endl;
}
Output:
bash % clang++ -O3 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 0 ms.
std::vector = 0 ms
bash % clang++ -O2 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 0 ms.
std::vector = 0 ms.
bash % clang++ -O1 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 89.945 ms.
std::vector = 14135.3 ms.
bash % clang++ -O0 -std=gnu++14 test.cpp && ./a.out
std::unique_ptr = 80.945 ms.
std::vector = 67521.1 ms.
Even with no writes or reallocations, std::vector is over 800 times slower than just using a new with a unique_ptr at -O0 and 150 times slower at -O1. What's going on here?
As #MartinSchlott points out, it is not designed for this task. A vector is for holding a set object instances, not an unstructured (from an array standpoint) buffer. Objects have destructors and constructors.
When the vector is destroyed, it calls the destructor for each element in it, even vector will call a destructor for each char in your vector.
You can see how much time it takes just to "destroy" the unsigned chars in this vector with this example:
#include <chrono>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
std::vector<unsigned char> allocateWithVector() {
return std::vector<unsigned char>(4000000); }
}
int main() {
auto start = std::chrono::system_clock::now();
for (long i = 0; i < 100; i++) {
auto leakThis = new std::vector<unsigned char>(allocateWithVector());
}
auto leak_end = std::chrono::system_clock::now();
for (long i = 0; i < 100; i++) {
auto myBuff = allocateWithVector();
}
auto vector_end = std::chrono::system_clock::now();
std::cout << "leaking vectors: = "
<< (leak_end - start).count() / 1000.0 << " ms." << std::endl;
std::cout << "destroying vectors = "
<< (vector_end - leak_end).count() / 1000.0 << " ms." << std::endl;
}
Output:
leaking vectors: = 2058.2 ms.
destroying vectors = 3473.72 ms.
real 0m5.579s
user 0m5.427s
sys 0m0.135s
Even when removing the destruction of the vector, it's still taking 2 seconds to just construct 100 of these things.
If you don't need dynamic resizing, or construction & destruction of the elements making up your buffer, don't use std::vector.
std::vector was MADE to be used in such cases. So, yes.
Yes, it is.
reserve is unnecessary in your case.
Yes, it will.
In addition - to ensure a minimum of allocated memory:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
m_pImageBuffer.swap(std::vector<unsigned char>(
pPixels, pPixels + uPixelCount));
// ... process image etc. ...
}
vector::assign does not change the amount of memory allocated, if the capacity is bigger than the amount needed:
Effects:
erase(begin(), end());
insert(begin(), first, last);
Please, consider this:
void MyClass::OnImageReceived(unsigned char *pPixels, unsigned int uPixelCount)
{
// called when a new image is available
if (m_pImageBuffer.size() != uPixelCount) // maybe just < ??
{
std::vector<unsigned char> temp;
temp.reserve(uPixelCount); // no initialize
m_pImageBuffer.swap(temp) ; // no copy old data
}
m_pImageBuffer.assign(pPixels, pPixels + uPixelCount); // no reallocate
// ... process image etc. ...
}
My point is that if you have a big picture and need a litter bigger pic, your old pic will get copy during the reserve and/or resize into the new allocated memmory, the excess of memmory initialized, and then rewrited with the new pic. You colud directly assing, but then you will no be able to use the info you have about the new size to avoid posible reallocations (maybe the implementation of assign is allready optimize for this simple case ????).
It depends.
If you access the data only through iterators and the [] operator, than its okay to use a vector.
If you have to give a pointer to functions which expect a buffer of e.g. bytes. It is not in my opinion. In this case You should use something like
unique_ptr<unsigned char[]> buf(new unsigned char[size])
is it as save as a vector, but instead of a vector you have maximum control of the buffer. A vector may reallocate a buffer or during a method/function call you may unintentionally make a copy of your whole vector. A easily made mistake.
The rule (for me) is. If you have a vector, use it like a vector. If you need a memory buffer, use a memory buffer.
As in a comment pointed out, the vector has a data method. This is C++. The freedom of using a vector as a raw buffer does not mend that you should use it as a raw buffer. In my humble opinion, the intention of a vector was to have a type save buffer with type save access system. For compatibility you can use the internal buffer for calls. The intention was not to use the vector as a smart pointer buffer container. For that, I use the pointer templates, signaling other user of my code that I use this buffer in a raw way. If I use vectors, I use them in the way they are intended to, not the possible ways they offer.
AS I got some blame here for my opinion (not recommendation) I want to add some words to the actual problem the op described.
If he expect always the same picture size, he should, in my opinion, use a unique_ptr, because that's what he is doing with it in my opinion. Using
m_pImageBuffer.resize(uPixelCount, 0);
zeros the buffer first before he copy the pPixel to it, a unnecessary time penalty.
If the pictures he is expecting of different size, he should, in my opinion, not use a vector during following reason. Especially in his code:
// called when a new image is available
if (m_pImageBuffer.size() != uPixelCount)
{
// resize image buffer
m_pImageBuffer.reserve(uPixelCount);
m_pImageBuffer.resize(uPixelCount, 0);
}
he will resize the vector, which is in fact a malloc and copy as long as the images are getting bigger. A realloc in my experience always leads to malloc and copy.
That is the reason I, especially in this situation, recommand the use of a unique_ptr instead of a vector.

How to perform deep copying of struct with CUDA? [duplicate]

This question already has answers here:
Copying a struct containing pointers to CUDA device
(3 answers)
Closed 5 years ago.
Programming with CUDA I am facing a problem trying to copy some data from host to gpu.
I have 3 nested struct like these:
typedef struct {
char data[128];
short length;
} Cell;
typedef struct {
Cell* elements;
int height;
int width;
} Matrix;
typedef struct {
Matrix* tables;
int count;
} Container;
So Container "includes" some Matrix elements, which in turn includes some Cell elements.
Let's suppose I dynamically allocate the host memory in this way:
Container c;
c.tables = malloc(20 * sizeof(Matrix));
for(int i = 0;i<20;i++){
Matrix m;
m.elements = malloc(100 * sizeof(Cell));
c.tables[i] = m;
}
That is, a Container of 20 Matrix of 100 Cells each.
How could I now copy this data to the device memory using cudaMemCpy()?
Is there any good way to perform a deep copy of "struct of struct" from host to device?
Thanks for your time.
Andrea
The short answer is "just don't". There are four reasons why I say that:
There is no deep copy functionality in the API
The resulting code you will have to writeto set up and copy the structure you have described to the GPU will be ridiculously complex (about 4000 API calls at a minimum, and probably an intermediate kernel for your 20 Matrix of 100 Cells example)
The GPU code using three levels of pointer indirection will have massively increased memory access latency and will break what little cache coherency is available on the GPU
If you want to copy the data back to the host afterwards, you have the same problem in reverse
Consider using linear memory and indexing instead. It is portable between host and GPU, and the allocation and copy overhead is about 1% of the pointer based alternative.
If you really want to do this, leave a comment and I will try and dig up some old code examples which show what a complete folly nested pointers are on the GPU.