Can cv::Mat be safely recreated from its bitwise-serialized form? - c++

Consider following code:
cv::Mat currentFrame; // some proper frame with allocated memory
std::vector<uint8_t> storage;
{
cv::Mat m1 = currentFrame.clone();
cv::Mat m2 = m1;
const auto *m1ptr = reinterpret_cast<const uint8_t *>(&m1);
storage.insert(storage.end(), m1ptr, m1ptr + sizeof(cv::Mat));
m1.addref();
}
{
cv::Mat m3;
uint8_t *dstPtr = reinterpret_cast<uint8_t *>(&m3);
std::copy_n(storage.begin(), sizeof(cv::Mat), dstPtr);
}
In the first scope I am working with a cv::Mat image, doing some copying to increase the refcount, and finally bitwise-serializing just the cv::Mat header (96 bytes) into the vector storage. Notice m1.addref(), where I increase the refcount by 1, so to avoid memory deallocation, when m1 and m2 get deleted, and refcount would drop to 0. Between the scopes, there is no actual cv::Mat pointing to allocated place in the memory, but the copy of such cv::Mat exists in the storage.
Then I try to restore it, by deserializing it from the storage. m3 is now a copy of already gone m1, it points to still allocated memory block, and refcount=1. So I would expect everything to work. But when we reach the end of the scope and destructor of m3 is called, I get invalid pointer exception. What is wrong with this design?

C++ objects are not just collections of bytes. You can't bitwise copy an arbitrary object into another object and pretend that you've recreated the original one. You can do it only for trivial types, and cv::Mat is not such a type. All tricks related to keeping matrix elements buffer from deallocation are irrelevant, because cv::Mat could have and actually does have other implementation details that prevent correct bitwise move.
Here is a simple example of a type that follows those details of cv::Mat:
struct S {
int* a; // = cv::Mat::step.p
int b; // = cv::Mat::step.buf
// other irrelevant data members including matrix elements buffer
S() {
a = &b;
}
~S() {
if (a != &b)
delete a;
}
};
std::vector<char> storage;
{
S s1;
auto ptr = reinterpret_cast<char*>(&s1);
storage.insert(storage.end(), ptr, ptr + sizeof(S));
}
{
S s2;
char* ptr = reinterpret_cast<char*>(&s2);
std::copy_n(storage.begin(), sizeof(S), ptr);
}
It should be pretty obvious what's wrong with bitwise overwriting s2 with bitwise-serialized s1: you set s2.a to an address of s1.b. If you're lucky to have s1 and s2 at the same address, nothing bad will happen. If they are at different addresses, you'll delete a variable on stack. That's how UB looks: sometimes your code appears to work, sometimes it crashes.
Here is a complete demo you can play with: https://godbolt.org/z/5ezcaWv7x

Related

Allocating an array of aligned struct

I'm trying to allocate an array of struct and I want each struct to be aligned to 64 bytes.
I tried this (it's for Windows only for now), but it doesn't work (I tried with VS2012 and VS2013):
struct __declspec(align(64)) A
{
std::vector<int> v;
A()
{
assert(sizeof(A) == 64);
assert((size_t)this % 64 == 0);
}
void* operator new[] (size_t size)
{
void* ptr = _aligned_malloc(size, 64);
assert((size_t)ptr % 64 == 0);
return ptr;
}
void operator delete[] (void* p)
{
_aligned_free(p);
}
};
int main(int argc, char* argv[])
{
A* arr = new A[200];
return 0;
}
The assert ((size_t)this % 64 == 0) breaks (the modulo returns 16). It looks like it works if the struct only contains simple types though, but breaks when it contains an std container (or some other std classes).
Am I doing something wrong? Is there a way of doing this properly? (Preferably c++03 compatible, but any solution that works in VS2012 is fine).
Edit:
As hinted by Shokwav, this works:
A* arr = (A*)new std::aligned_storage<sizeof(A), 64>::type[200];
// this works too actually:
//A* arr = (A*)_aligned_malloc(sizeof(A) * 200, 64);
for (int i=0; i<200; ++i)
new (&arr[i]) A();
So it looks like it's related to the use of new[]... I'm very curious if anybody has an explanation.
I wonder why you need such a huge alignment requirement, moreover to store a dynamic heap allocated object in the struct. But you can do this:
struct __declspec(align(64)) A
{
unsigned char ___padding[64 - sizeof(std::vector<int>)];
std::vector<int> v;
void* operator new[] (size_t size)
{
// Make sure the buffer will fit even in the worst case
unsigned char* ptr = (unsigned char*)malloc(size + 63);
// Find out the next aligned position in the buffer
unsigned char* endptr = (unsigned char*)(((intptr_t)ptr + 63) & ~63ULL);
// Also store the misalignment in the first padding of the structure
unsigned char misalign = (unsigned char)(endptr - ptr);
*endptr = misalign;
return endptr;
}
void operator delete[] (void* p)
{
unsigned char * ptr = (unsigned char*)p;
// It's required to call back with the original pointer, so subtract the misalignment offset
ptr -= *ptr;
free(ptr);
}
};
int main()
{
A * a = new A[2];
printf("%p - %p = %d\n", &a[1], &a[0], int((char*)&a[1] - (char*)&a[0]));
return 0;
}
I did not have your align_malloc and free function, so the implementation I'm providing is doing this:
It allocates larger to make sure it will fit in 64-bytes boundaries
It computes the offset from the allocation to the closest 64-bytes boundary
It stores the "offset" in the padding of the first structure (else I would have required a larger allocation space each time)
This is used to compute back the original pointer to the free()
Outputs:
0x7fff57b1ca40 - 0x7fff57b1ca00 = 64
Warning: If there is no padding in your structure, then the scheme above will corrupt data, since I'll be storing the misalignement offset in a place that'll be overwritten by the constructor of the internal members.
Remember that when you do "new X[n]", "n" has to be stored "somewhere" so when calling delete[], "n" calls to the destructors will be done. Usually, it's stored before the returned memory buffer (new will likely allocate the required size + 4 for storing the number of elements). The scheme here avoid this.
Another warning: Because C++ calls this operator with some additional padding included in the size for storing the array's number of elements, you'll might still get a "shift" in the returned pointer address for your objects. You might need to account for it. This is what the std::align does, it takes the extra space, compute the alignment like I did and return the aligned pointer. However, you can not get both done in the new[] overload, because of the "count storage" shift that happens after returning from new(). However, you can figure out the "count storage" space once by a single allocation, and adjust the offset accordingly in the new[] implementation.

C++ cases of deleting

If I have this two vectors of pointers to MyClass
vector<MyClass*> A;
vector<MyClass*> B;
where A is full and B is empty and I do this operation:
B = A;
Have I to delete the pointers of both vectors or just one?
If I have a dynamic object like this:
MyClass *p = new MyClass;
And this pointer:
MyClass *p2;
If I do this operation:
p2 = p1;
Have I to delete both p and p2 or just one of two?
The pointers are pointing to the same piece of memory, so you only need to delete it once.
You get undefined behaviour if you try to delete an object through a pointer more than once.
A pointer is just(*1) a regular variable containing an unsigned integer value. This value is an address in memory where the pointed-to-value is stored.
In simpler terms, you can think of a pointer as an array index to memory.
byte ram[16 * 1024 * 1024 * 1024]; // 16Gbs of memory.
size_t index = 10000; // indexes the 10,000th byte of ram.
byte* ptr = ram+ 10000; // ptr contains the same actual value as index
ptr = &ram[10000]; // same value again
ptr = ram;
ptr += 10000; // same value again
When you declare the variable as a pointer, you are extending it's contract within the language. Although, underneath, it is still just a regular variable, the language will treat your interactions with it differently because it is aware that you are expecting to use it to reference memory like this.
So, to answer your original question: You need to match every alloc with a single, corresponding delete. This is a concept called "ownership".
char* a = new char[64];
char* b = a;
Both a and b contain the same value, the address of our 64 bytes, but only one of them "owns" the allocation.
That determination is up to the programmer, and is deterministic: Which pointer will last longest? Which will try to use the pointer last?
char* a = new char[64];
if (a != nullptr)
{
char* b = a;
strcpy(b, "hello world");
// <-- end of b's lifetime.
}
std::cout << a << '\n';
If we deleted b at the end of it's lifetime, a would still point to it. The actual underlying memory is untouched, the problem is that the memory could be allocated to someone else in the mean time. (You forget your watch in the drawer of a hotel. If you go back a week after your stay, will your watch still be in the top drawer?)
In the above example, clearly a is more authoritative for the allocation, so we should delete after a has finished using it.
char* a = new char[64];
if (a != nullptr)
{
char* b = a;
strcpy(b, "hello world");
// <-- end of b's lifetime.
}
std::cout << a << '\n';
delete [] a; // we used new [] match with delete []
Pointer management can easily be difficult, and has been causing bugs in C code since C existed.
C++ provides several classes that encapsulate the properties of ownership. std::unique_ptr is a single point of ownership for allocations ideal for when you have a container of pointers.
std::vector<std::unique_ptr<YourClass>> myVector;
myVector.emplace_back(new YourClass));
when this vector goes out of scope, the unique_ptr objects will go out of scope, at which point they will delete their allocations. Problem solved.
There is also std::shared_ptr if you may need the ownership to be dynamic...
std::vector<std::shared_ptr<MailItem>> inbox;
std::set<std::shared_ptr<MailItem>> urgent;
// incoming mail goes into inbox, copied to urgent if its a priority...
for (auto it : inbox)
{
if (it->>IsPriority()) {
urgent.insert(it);
// now there are TWO pointers to the same item.
}
}
In the above case, the user can delete an urgent item from inbox but the item still exists. shared_ptr uses a "reference counter" to know how many pointers own the object. In most cases, this is going to be more complex than you need and unique_ptr will be sufficient.
(*1 There are some platforms where pointers are more than just a single variable but that's kind of advanced and you probably don't need to worry about that until such time as you work on such a platform)

C++ My String class: Pointer doesn't work

I'm building my own string class in c++ 11 and I have a memory problem.
in main:
MyString str1; //Works ok, constructor creates empty char array.
const char* pointer1 = str1.c_str(); //Return the pointer to the array.
str1.Reserve(5);
// Now, when I use the Reverse method in string1, Pointer1 is
// pointing to the old memory address.
How to I change the array data in str1, but to the memory address?
With aother words, How do I fix this so that:
pointer1 == str1.c_str();
Reserve method:
void reserve(int res)
{
capacity = NewSize(size + res,0 , capacity); //Method to find the best cap.
char* oldData = data;
data = new char[capacity];
memcpy(data, oldData, capacity);
oldData = data;
//delete[] data;
data[(size)] = '\0';
}
This returns all the right data, but when I do "oldData = data", the memory address is lost.
I appreciate all help, thanks!
I think what you are asking is if there is a way to get a return value from your string class which will always point to the current string array. There are a number of ways to do this but generally this indicates bad design/implementation.
The more normal way to do this would be to advise API users that the result of c_str() is invalidated by any subsequent modifications to the object: don't keep the pointer, just call c_str() again.
Two obvious options are: a) a pointer to the pointer, very dangerous because now someone outside your class can tweak it, b) provide a wrapper class which encapsulates a pointer-to-pointer without allowing modifications.
template<typename T>
struct ReadOnlyPointer {
T* m_ptr;
... operator * ...
... operator -> ...
... operator T ...
};
ReadOnlyPointer<const char*> pointer = str1.pointer();
There also appear to be at least a couple of issues with your "reserve" function.
You push a '\0' at data[0] even though size might be zero.
MyString a;
a.reserve(0); // crash? you wrote to the first byte of a zero length array.
After copying the data from oldData to data, for some reason you assign the value of 'data' to 'oldData' and then never use 'oldData' again - this is a memory leak.
Your memcpy uses 'capacity' instead of 'size' so it may be over-copying.
Consider instead:
// ensure we have an additional 'res' bytes.
// caution: unlike stl and boost reserve, these are
// additional bytes, not total bytes.
void reserve(int res)
{
int newCapacity = NewSize(m_size + res, 0, m_capacity); //Method to find the best cap.
if(newCapacity <= m_capacity)
return;
char* newData = new char[newCapacity];
memcpy(newData, m_data, m_size);
delete[] m_data; // release the old allocation
m_data = newData;
m_capacity = newCapacity;
}
The extra data[(size)] = '\0'; could be the cause of your string becoming truncated if you are not changing the value of size elsewhere in your code.

How to return a float array in c and save it an array of floats to use later?

I have a C++ function which returns a std::vector<float>.
I am interfacing with some C code.
How do I change this C++ function so that it returns some pointer to a float array, and how do I save this returned array so that I can use it in my C code?
You can get a pointer to a "raw" array with std::vector::data or &my_vector[0] if C++11 is not available. However, if a vector operation forces the vector to be resized then the raw storage will move around in memory and this pointer will no longer be safe to use. If there is any possibility of this happening, you will need to allocate separate storage (e.g. by creating a copy of the vector) and provide a pointer to that instead.
Update: Woodrow's comment made me notice that you are actually after returning a pointer from a function. You can only return pointers to heap-allocated memory, so you cannot use a local vector (or any other type of stack-allocated memory) to do this.
From a C point of view, vector<float> does two things:
Contain some floats
Automatically free the memory it uses
Since 2 is an alien concept to C (nothing much happens automatically, certainly not freeing memory), there's no simple replacement. Basically you have three options. They are the same as the three options you have when you want functions to "return strings" in C, although here we need to tell the caller both a pointer and a length.
In my opinion, the third option is "the right answer", in the sense that it's the one you try first in your design, and if the design looks OK you stick with it. The first and second can be provided as convenience functions in cases where the calling code will really benefit from them, either wrapped around or alongside the third.
Return allocated memory
size_t c_wrapper(float **pResult) {
try {
std::vector<float> vec(cpp_function());
*pResult= (float*) std::malloc(vec.size() * sizeof(float));
if (!*pResult) { /* handle the error somehow */ }
std::copy(vec.begin(), vec.end(), *pResult);
return vec.size();
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Simple calling code.
Downside: The caller has to free the memory, even if the size is known in advance and the data would happily fit in a local array variable. Might be slow due to memory allocation.
Model: strdup (Posix)
Use shared static-duration resources
See jrok's answer:
size_t c_wrapper(float **pResult) {
try {
static std::vector<float> vec;
vec = cpp_function(); // or cpp_function().swap(vec) in C++03
*pResult = &vec[0];
return vec.size();
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Ridiculously simple calling code.
Downside: There is only one instance of save in the program, so the returned pointer only points to the correct data until the next time c_wrapper is called. In particular, this is very thread-unsafe. If the result is very large, then that memory is wasted from the time the caller no longer needs it until the time the function is next called.
Model: strtok, gethostbyname.
Write the data into a buffer provided by the caller
size_t c_wrapper(float *buf, size_t len) {
try {
std::vector<float> vec(cpp_function());
if (vec.size() <= len) {
std::copy(vec.begin(), vec.end(), buf);
}
return vec.size()
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Most flexible.
Downside: The caller has to pass in a big enough buffer (assuming cpp_function behaves consistently, caller can find out the size by calling the function with size 0 and a null pointer, get a big enough buffer from somewhere, then call the function again).
Model: strcpy, snprintf, getaddrinfo.
You could save the returned temporary vector in a vector object with static storage duration.
std::vector<float> foo()
{
return std::vector<float>();
}
float* call_foo_and_get_pointer()
{
static std::vector<float> save; // this line is executed only at the first
// call to enclosing function
save = foo();
return save.data(); // or &data[0]
}
The pointer returned from call_foo_and_get_pointer is guaranteed to stay valid until the next call to it.
#include <vector>
#include <iostream>
int main()
{
std::vector<float> vec;
vec.push_back(1.23);
vec.push_back(3.123);
int len = vec.size();
float *arr = new float[len];
std::copy(vec.begin(),vec.end(),arr);
for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i){
std::cout << arr[i] << "\n";
}
delete [] arr;
return 0;
}

How to copy values from one pointer to another

I have the following pointer:
jfloat *verticesLocal;
And I want make a new copy to:
jfloat *vertices;
I want to copy the values from verticesLocal to vertices.
How can I do that? I've just tried the following command, but it doesn't work:
memcpy(vertices, verticesLocal, numVerticesLocal * sizeof(jfloat));
I can't see the error because I'm working with Android native code. Sorry.
The idea of "copying a pointer", when taken literally, is nothing more than a simple assignment.
int x = 5;
int* p1 = &x;
int* p2 = p1; // there, we copied the pointer.
In this case, both p1 and p2 point to the same data - the int variable x. However, because this is so trivial, I'm inclined to think that what you really are asking about is how to copy the data that the pointer points to.
In this case, it depends on the data type. If the pointer points to a simple buffer of PODs, this involves allocating a separate buffer, and then using something like memcpy (or preferably std::copy) to copy the data. For example:
int* p1 = new int[100];
// ... fill p1 with values
int* p2 = new int[100]; // create a new buffer
std::copy(p1, p1 + 100, p2); // copy the data into p2
Or, you can use memcpy to copy the buffer byte-by-byte, since the buffer contains PODs.
memcpy(p2, p1, 100 * sizeof(int));
However, if the pointed-to data is not a simple buffer, but rather a C++ object, you can't use memcpy. You need to perform a deep copy of the object, (usually using the object's copy constructor) to get a clone of the object. How this is done, or whether it's even possible, depends on the object. (Some objects are noncopyable.)
I have no clue what a jfloat is, but if the object is, for example, an std::string, you would just do something like:
std::string* s1; // assume this points to a valid string
std::string* s2 = new std::string();
*s2 = *s1; // copies s1 using s2's assignment operator
In this contrived example it would be preferable to avoid heap-allocation altogether, and just use stack variables. But it demonstrates the idea of copying a heap-allocated object.
malloc first, then do your memcpy.
If you are copying the pointer, it is a simple assignment:
jfloat* verticesLocal; // assuming is is allocated already
jfloat* newVertices = verticesLocal;
IF you mean you want to copy the data the point points to, you have to allocate the memory for the new block of memory first:
// assume jfloat* verticesLocal is pointing to a valid memory block of size i
jfloat* newVertices = new jfloat[i];
memcpy(newVertices, verticesLocal, i * sizeof(jfloat));
this is how you copy an array buffer :
unsigned char *pBufferSrc = new unsigned char[10];
unsigned char *pBufCpd = new unsigned char[10];
for (int i = 0; i < 10; i++)
pBufferSrc[i] = i; // pBufferSrc = [0,1,2,3,4,5,6,7,8,9]
memcpy(pBufCpd, pBufferSrc, 10); // data from pBufferSrc is copied to pBufCpd (0,1,2,..9)
delete []pBufferSrc; // if even pBufferSrc buffer gets deleted, pBufCpd still has the data