Why are the matrices not initialized/printed correctly? - c++

I am playing around with cv::Mat and think my code really behaves weird, although I follow the syntax described in here.
Code:
std::cout << "parameter for matrices: " << "x = " << X << " y = " << Y << " psi = " << Psi << std::endl;
double dataRot[] = { cos(Psi), -sin(Psi), sin(Psi), cos(Psi) };
double dataTrans[] = { X, Y };
cv::Mat matRot(2, 2, CV_32FC1, dataRot);
cv::Mat matTrans(2, 1, CV_32FC1, dataTrans);
std::cout << "matRot = " << matRot.at<double>(0,0) << "," << matRot.at<double>(0,1) << ";" << matRot.at<double>(1,0) << "," << matRot.at<double>(1,1) << std::endl;
std::cout << "matRot = " << matRot << std::endl;
std::cout << "matTrans = " << matTrans.at<double>(0,0) << "," << matTrans.at<double>(0,1) << std::endl;
std::cout << "matTrans = " << matTrans << std::endl;
matOut = matRot*matIn + matTrans*cv::Mat::ones(1, matIn.cols, CV_32FC1);
Output:
parameter for matrices: x = 20.5 y = 20 psi = 0
matRot = 1,-0;-0,0
matRot = [0, 1.875;
0, -0]
matTrans = 20.5,20
matTrans = [0; 2.8203125]
Why is the identity matrix not initalized correctly?
And why does the second way of printing a matrix deliver wrong results?
Any help is appreciated.

Since you're working with double, the OpenCV matrix type should be CV_64FC1:
cv::Mat matRot(2, 2, CV_64FC1, dataRot);
cv::Mat matTrans(2, 1, CV_64FC1, dataTrans);
For simplicity, you can also use:
cv::Matx22d matRot(cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Matx21d matTrans(X, Y);
or:
cv::Mat1d matRot = (cv::Mat1d(2,2) << cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Mat1d matTrans = (cv::Mat1d(2,1) << X, Y);
and access values like:
std::cout << matRot(row, col);

Related

Out of bounds index returns correct values from vector created in chibi scheme

I've embedded chibi scheme into my C++ application and am trying to create a float vector with a size of 3 in scheme, and then get the individual values of that vector back into my c++ program, however when I attempt to do so I only get the correct results if I use indexes beyond the size of the vector. As you can see below I verify the size of the vector.
test.scm
(define (test-vec in-a in-b)
(let ((vec (vector (* 3.1 in-a) (* 4.1 in-b) 5.0)))
(display "From Scheme: ")
(display vec)
(display "\n")
vec))
test.cpp
#include <iostream>
#include <chibi/eval.h>
int is_defined(sexp ctx, const char *sym)
{
sexp_gc_var1(ret);
sexp_gc_preserve1(ctx, ret);
ret = sexp_eval_string(ctx, sym, -1, NULL);
int defined = sexp_procedurep(ret);
sexp_gc_release1(ctx);
return defined;
}
int main()
{
float returnA, returnB, returnC, returnD, returnE, returnF;
sexp_scheme_init();
sexp ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0);
sexp_load_standard_env(ctx, NULL, SEXP_SEVEN);
sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1);
// Load the scheme file and create temp variables to pass the values to chibi
sexp_gc_var6(inAVal, inASym, inBVal, inBSym, returnedVector, filePath);
sexp_gc_preserve6(ctx, inAVal, inASym, inBVal, inBSym, returnedVector, filePath);
filePath = sexp_c_string(ctx, "test.scm", -1);
sexp_load(ctx, filePath, NULL);
// Ensure our procedure is defined
if(is_defined(ctx, "test-vec"))
std::cout << "test-vec is defined" << std::endl;
// Create the values and create the symbols
inAVal = sexp_make_flonum(ctx, 1.0);
inASym = sexp_intern(ctx, "a", -1);
inBVal = sexp_make_flonum(ctx, 2.0);
inBSym = sexp_intern(ctx, "b", -1);
// Bind the values to the symbols and pass them to chibi
sexp_env_define(ctx, sexp_context_env(ctx), inASym, inAVal);
sexp_env_define(ctx, sexp_context_env(ctx), inBSym, inBVal);
// Evaluate the expression and store the result
returnedVector = sexp_eval_string(ctx, "(test-vec a b)", -1, NULL);
std::cout << "Vector size: " << sexp_vector_length(returnedVector) << std::endl;
// I would expect this to return the expected results?
returnA = sexp_flonum_value(sexp_vector_ref(returnedVector, 0));
returnB = sexp_flonum_value(sexp_vector_ref(returnedVector, 1));
returnC = sexp_flonum_value(sexp_vector_ref(returnedVector, 2));
std::cout << "Vector[0] = " << returnA << "\nVector[1] = " << returnB << "\nVector[2] = " << returnC << std::endl << std::endl;
// If I index outside of the range of the vector, it gives me the correct results?
returnD = sexp_flonum_value(sexp_vector_ref(returnedVector, 0));
returnE = sexp_flonum_value(sexp_vector_ref(returnedVector, 3));
returnF = sexp_flonum_value(sexp_vector_ref(returnedVector, 4));
std::cout << "Vector[0] = " << returnD << "\nVector[3] = " << returnE << "\nVector[4] = " << returnF << std::endl;
sexp_gc_release6(ctx);
}
Which gives me the output:
test-vec is defined
From Scheme: #(3.1 8.2 5.0)
Vector size: 3
Vector[0] = 3.1
Vector[1] = 3.1
Vector[2] = 8.2
Vector[0] = 3.1
Vector[3] = 8.2
Vector[4] = 5
How come indexing beyond the length of the vector is giving me the correct values?
Figured out the issue. It's because sexp_vector_ref(vec, i) evaluates to
#define sexp_vector_ref(x,i) (sexp_vector_data(x)[sexp_unbox_fixnum(i)])
and sexp_unbox_fixnum(i) evaluates to
#define sexp_unbox_fixnum(n) (((sexp_sint_t)((sexp_uint_t)(n) & ~SEXP_FIXNUM_TAG))/(sexp_sint_t)((sexp_sint_t)1<<SEXP_FIXNUM_BITS))
Which when we just pass in straight integers
std::cout << "Unboxed fixnums: " <<
sexp_unbox_fixnum(0) << " " <<
sexp_unbox_fixnum(1) << " " <<
sexp_unbox_fixnum(2) << " " <<
sexp_unbox_fixnum(3) << " " <<
sexp_unbox_fixnum(4) << std::endl;
gives us the output
Unboxed fixnums: 0 0 1 1 2
However if we first convert them into the proper types that chibi expects, like so
std::cout << "Fixnum: " <<
sexp_unbox_fixnum(sexp_make_fixnum(0)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(1)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(2)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(3)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(4)) << std::endl;
we get the proper output
Fixnum: 0 1 2 3 4
Solution: Use the correct types when indexing

Pointer/Array Indexing Returning Unexpected Values

I am implementing code for convolution in C++ (I know it exists already but I'm just doing it for practice since I'm a beginner), and while I can get the correct output, there are certain methods I'm trying that are giving unexpected output depending on how I access the values of the convolution that I store in an array and I'm not sure why.
The function code that works, whether I access the values by array indexing or with pointer incrementing, is:
void conv(int M, int* h, int L, int* x, int* y) {
int n, m = 0;
for (n = 0; n < L + M - 1; n++) {
for (m = std::max(0, n - L + 1); m <= std::min(n, M - 1); m++) {
*(y+n) += *(h + m) * *(x + n - m);
};
std::cout << "using array index: " << std::endl;
std::cout << "n = " << n << " " << "y = " << y[n] << " " << std::endl;
std::cout << std::endl;
std::cout << "using pointer: " << std::endl;
std::cout << "n = " << n << " " << "y = " << *(y+n) << " " << std::endl;
std::cout << std::endl;
//y++;
}
}
However, if I make slight changes to this (numbered below):
void conv(int M, int* h, int L, int* x, int* y) {
int n, m = 0;
for (n = 0; n < L + M - 1; n++) {
for (m = std::max(0, n - L + 1); m <= std::min(n, M - 1); m++) {
*y += *(h + m) * *(x + n - m); //[1]
};
std::cout << "using array index: " << std::endl;
std::cout << "n = " << n << " " << "y = " << y[n] << " " << std::endl;
std::cout << std::endl;
std::cout << "using pointer: " << std::endl;
std::cout << "n = " << n << " " << "y = " << *y << " " << std::endl; //[2]
std::cout << std::endl;
y++; //[3]
}
}
In this case, only accessing the values via pointer provides the correct output, while accessing it via array indexing provides random garbage.
My test code is:
int main()
{
const int M = 5; const int L = 6;
int y[M + L - 1] = {};
int x[L] = { 1, -2, 5, 3, 8, -4 };
int h[M] = { 1,2,3,4,5 };
int* yPtr = y; int* hPtr = h; int* xPtr = x;
conv(M, hPtr, L, xPtr, yPtr);
std::cout << "value after leaving conv" << std::endl;
for (int i = 0; i < M+L-1; i++) {
std::cout << "i = " << i << " " << "y = " << y[i] << std::endl;
}
}
which always provides the correct output even when accessing the array elements in the for loop of the conv provides the incorrect output.
For reference, the correct output is y = {1, 0, 4, 11, 26, 31, 53, 35, 24, -20}.
What am I doing wrong in the second example of conv to be getting the wrong values when using array indexing?
In the second version of the code, you are incrementing y as you go through the loop, so y[n] in the second version is equivalent to y[2*n] in the first. Once n reaches half the size of the array, y[n] is past the end of the array, thus garbage. *y is equivalent to y[0].
Your example is sufficiently weird to be a little difficult to read, but from your second version, this is fishy:
std::cout << "n = " << n << " " << "y = " << y[n] << " " << std::endl;
You're incrementing y as you go, so y[n] is going to go to weird places fast.
I saved Y as int * yOrig = y; and then used that, and I think I'm getting the output you expect, but I'm not sure.

How to get pixel value from the contoured image with mask?

I tried to extract average pixel values (R, G, B) from the contoured image. However, my problem is when I applied the code below, something strange values were observed.
int main(){
cv::Mat star = imread("C:\\Users\\PC\\Desktop\\star\\starcircle.png");
cv::Mat mask = cv::Mat::zeros(star.rows, star.cols, CV_8UC1);
cv::Mat frame;
double b, g, r = 0.0;
cv::imshow("Original", star);
cv::cvtColor(star, frame, CV_BGR2HSV);
cv::inRange(frame, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
cv::Scalar temp = mean(mask);
cout << "avg_R: " << temp[2] << " \n"; // red value
cout << "avg_G: " << temp[1] << " \n"; // green value
cout << "avg_B: " << temp[0] << " \n\n"; // blue value
cv::imshow("result", result);
cv::waitKey(-1);
return 0;
}
And I got the correct images for the result like below.
I want to read pixel values only for yellow part, not for outside of mask.
And I have another code for read out pixel values in the yellow parts, but it showed the same result.
int main(){
cv::Mat star = imread("C:\\Users\\PC\\Desktop\\star\\starcircle.png");
cv::Mat mask = cv::Mat::zeros(star.rows, star.cols, CV_8UC1);
cv::Mat frame;
double b, g, r = 0.0;
cv::imshow("Original", star);
cv::cvtColor(star, frame, CV_BGR2HSV);
cv::inRange(frame, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
int hei = star.rows;
int wid = star.cols;
int corow = hei * wid;
double b, g, r = 0.0;
for (int x = 0; x < hei; x++) {
for (int y = 0; y < wid; y++) {
if (mask.at<unsigned char>(x, y) > 0) {
b += result.at<Vec3b>(x, y)[0];
g += result.at<Vec3b>(x, y)[1];
r += result.at<Vec3b>(x, y)[2];
}
else {
}
}
}
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
}
Please help me to revise the error.
Thank you in advance.
A few things:
Your variables names and Mat types are at least confusing. Use proper names for the variables, and use Mat_<T> whenever possible (I'd say always).
To get the mean you should divide by the number of pixels in the mask, not by total number of pixels.
you should consider using cv::mean
you need cv::waitKey() to actually see your cv::imshow
Check the code:
#include <opencv2\opencv.hpp>
int main()
{
cv::Mat3b star = cv::imread("path/to/image");
cv::imshow("Original", star);
cv::Mat3b hsv;
cv::cvtColor(star, hsv, cv::COLOR_BGR2HSV);
cv::Mat1b mask;
cv::inRange(hsv, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
// Change to 'false' to see how to use the 'cv::mask' approach
if (true)
{
double blue, green, red = 0.0;
int counter = 0;
for (int r = 0; r < star.rows; r++)
{
for (int c = 0; c < star.cols; c++)
{
if (mask(r, c) > 0)
{
++counter;
blue += star(r, c)[0];
green += star(r, c)[1];
red += star(r, c)[2];
}
}
}
// Avoid division by 0
if (counter > 0)
{
blue /= counter;
green /= counter;
red /= counter;
}
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
std::cout << "avg_R: " << red << " \n";
std::cout << "avg_G: " << green << " \n";
std::cout << "avg_B: " << blue << " \n\n";
}
else
{
cv::Scalar mean_value = cv::mean(star, mask);
double blue = mean_value[0];
double green = mean_value[1];
double red = mean_value[2];
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
std::cout << "avg_R: " << red << " \n"; // red value
std::cout << "avg_G: " << green << " \n"; // green value
std::cout << "avg_B: " << blue << " \n\n"; // blue value
}
cv::waitKey();
}
I see several errors in your code:
cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
cv::Scalar temp = mean(mask);
If result is of type CV_8UC1 then you copyTo one channel? (The C1 from CV_8U means one channel). Then you use star.type() where the value to be set should be... You do also the mean to a mask, which will give you a scalar with only one channel set, since it is a binary image of type CV_8UC1... for it to work, it should be:
cv::Mat result = cv::Mat(star.rows, star.cols, star.type(), cv::Scalar::all(0));
star.copyTo(result, mask);
cv::Scalar temp = mean(result);
For the second part, it is ok to add it like that, however if you have not fixed the previous error... I think it should give you segmentation error at some point or weird results if you are lucky. Finally the result part you have this:
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
but corow should be the non zero points of the mask, so it should be:
corow = cv::countNonZero(mask);
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
if not it will give you a smaller number, since it is divided with a a number that includes the black points which do not contribute.
As an extra note, you should use more OpenCV functions... in this case cv::mean does the same thing, if not you can simplify it with sum and divide like:
cv::Scalar summed = cv::sum(result);
cv::Scalar mean = summed / static_cast<double>(cv::countNonZero(mask));
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << std::endl << std::endl;
std::cout << "avg_R: " << mean[2] << std::endl; // red value
std::cout << "avg_G: " << mean[1] << std::endl; // green value
std::cout << "avg_B: " << mean[0] << std::endl << std::endl; // blue value
This is assuming you did the star.copyTo(result, mask); line
Read about cv::Mat::at: first row, second col. Not (x, y)!
See you on cv::mean: it can work with mask.
Right initialization: double b = 0.0, g = 0.0, r = 0.0;
int corow = 0; And inside loop ++corow if mask > 0.

weird glm::mat2x4 assignment behaviour

I am trying to load freetype chars, stuff them into a texture as subimages and then render them instanced.
While most of it seems to work, right now I have a problem with storing the texture coordinates into a glm::mat2x4 matrix.
As can be seen below each character has a struct with information I right now deem necessary, including a matrix called face, which should store the texture coordinates.
But when it comes to assigning the coordinates, after leaving the loop in which it takes place, suddenly all the values go crazy, without any (wanted/ intended) operation taking place from my side.
After creating the texture atlas with freetype and putting all my structs into the map, I assign the width and height of my texture aw & ah to a storage class called c_atlas.
I calculate the texture coordinates in the loop shown below, make the glm::mat2x4 a 0.0f matrix and then stuff them into it. Couting them into the console gives the values I want.
After leaving the for loop I start another one, browsing over the matrix and cout them into the console, which gives me more or less random values in the range of e^-23 to e^32.
All of this happens in namespace foo and is called in a constructor of a class in the same namespace (sth. like this:)
foo::class::constructor()
{
call_function();
}
int main()
{
foo::class c;
c.call_function();
}
I crafted a minimum working example, but unfortunatly I am not able to replicate the error.
So I have the following loop running (a part of call_function():
namespace foo
{
namespace alphabet
{
const char path_arial[] = "res/font/consola.ttf";
class character
{
public:
glm::vec2 advance;
glm::vec2 bearing;
glm::vec2 size;
glm::vec2 offset;
glm::mat2x4 face;
};
std::map<char, character> char_map;
FT_Library m_ftlib;
FT_Face m_ftface;
GLuint m_VBO, m_VAO;
}
c_atlas ascii;
}
void foo::call_function()
{
//creating all the charactur structs with freetype and store them in the char_map
std::ofstream f("atlas_data.csv", std::ios::openmode::_S_app);
f << "letter;topleft.x;topleft.y;topright.x;topright.y;bottomright.x;bottomright.y;bottomleft.x;bottomleft.y" << std::endl;
for(auto c : alphabet::char_map)
{
std::cout << "b4: " << c.second.offset.x;
c.second.offset /= glm::vec2(aw,ah);
std::cout << "\nafter: " << c.second.offset.x << std::endl;
glm::vec2 ts = c.second.size/glm::vec2(aw,ah);
//couts the right values
uint16_t n = 0;
c.second.face = glm::mat2x4(0.0f);
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " at init:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//couts the right values
c.second.face[0][n++] = c.second.offset.x;
c.second.face[0][n++] = c.second.offset.y;
c.second.face[0][n++] = c.second.offset.x+ts.x;
c.second.face[0][n++] = c.second.offset.y;
n = 0;
c.second.face[1][n++]= c.second.offset.x+ts.x;
c.second.face[1][n++] = c.second.offset.y+ts.y;
c.second.face[1][n++] = c.second.offset.x;
c.second.face[1][n++]= c.second.offset.y+ts.y;
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " assigned:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//still couts the right values
f << (char)c.first << ";" << c.second.face[0].x << ";" << c.second.face[0].y << ";" << c.second.face[0].z << ";" << c.second.face[0].w << ";" << c.second.face[1].x << ";" << c.second.face[1].y << ";" << c.second.face[1].z << ";" << c.second.face[1].w << std::endl;
//the file also have the right values
}
f.close();
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//yet here all the values totally off track, i.e. e^32 or e^-23 (while they should all be between 0.01f - 1.0f)
for(auto i : alphabet::char_map)
{
std::cout << "\ntopleft:\n";
std::cout << "X: " << i.second.face[0].x << " | " << "Y: " << i.second.face[0].x;
std::cout << "\ntopright:\n";
std::cout << "X: " << i.second.face[0].z << " | " << "Y: " << i.second.face[0].w;
std::cout << "\nbotleft:\n";
std::cout << "X: " << i.second.face[1].x << " | " << "Y: " << i.second.face[1].x;
std::cout << "\nbotright:\n";
std::cout << "X: " << i.second.face[1].z << " | " << "Y: " << i.second.face[1].w;
}
}
my mwe:
#include <iostream>
#include <string>
#include "glm/glm.hpp"
#include "GL/gl.h"
#include <map>
struct bin
{
glm::mat2x4 mat;
};
int main( int argc, char *argv[] )
{
std::map<char, bin> bucket;
uint16_t r = 0;
for(uint16_t n = 0; n < 7; ++n)
{
glm::vec4 v = glm::vec4(0.12128f, 0.12412f, 0.15532f, 0.23453f);
bin b;
r = 0;
b.mat[0][r++] = v.x;
b.mat[0][r++] = v.y;
b.mat[0][r++] = v.z;
b.mat[0][r++] = v.w;
r = 0;
b.mat[1][r++] = v.x;
b.mat[1][r++] = v.y;
b.mat[1][r++] = v.z;
b.mat[1][r++] = v.w;
bucket[n] = b;
}
for(auto it : bucket)
{
r = 0;
std::cout << "0:\t" << it.second.mat[0][0] << "\t" << it.second.mat[0][1] << "\t" << it.second.mat[0][2] << "\t" << it.second.mat[0][3] << "\n";
r = 0;
std::cout << "1:\t" << it.second.mat[1][0] << "\t" << it.second.mat[1][1] << "\t" << it.second.mat[1][2] << "\t" << it.second.mat[1][3] << std::endl;
}
return 0;
}
Right now I am totally lost, especially as my mwe works fine.
I am clueless what goes wrong after leaving the for-loop, so thanks for any thought on that!
Indeed, I could just rewrite that section and hope it would work - as my mwe does. But I would like to find out/ get help on finding out what exactly happens between the "assign" for loop and the "retrieve" for loop. Any ideas on that?
I made it work for me now:
Appartenly assigning the values this way:
for(auto c : alphabet::char_map)
{
c.second.face[0][n++] = c.second.offset.x;
//and so on
}
Did not work properly (for whatever reason..)
Changing this into a for(uint16_t i = 32; i < 128; ++i) worked for me. Also it was just the assigning loop, the auto-iterating ofer the map elsewhere works just fine.

Making POD classes movable

I have a POD class and I want to make it movable for efficiency. I keep all the data in a std::array member object, and I make my public member variables references to parts of this std::array object. By doing this, now I am able to move the entire data by moving the std::array instance in the move constructor (I know that it is not literally a POD class anymore after writing constructors.).
Is this a good method of doing this? Does it actually move the data? See the code output below: After moving the std::array, I observe that both objects have the same values. It looks like it doesn't move, but it copies the data. What is the problem here?
#include <array>
class MyPodClass
{
private:
typedef double TYPE_x;
typedef double TYPE_y;
typedef double TYPE_z;
typedef int TYPE_p;
typedef int TYPE_r;
typedef int TYPE_s;
typedef char TYPE_k;
typedef char TYPE_l;
typedef char TYPE_m;
typedef float TYPE_a;
typedef float TYPE_b;
typedef float TYPE_c;
enum TypeSizes
{
STARTING_POSITION_x = 0,
STARTING_POSITION_y = STARTING_POSITION_x + sizeof(TYPE_x),
STARTING_POSITION_z = STARTING_POSITION_y + sizeof(TYPE_y),
STARTING_POSITION_p = STARTING_POSITION_z + sizeof(TYPE_z),
STARTING_POSITION_r = STARTING_POSITION_p + sizeof(TYPE_p),
STARTING_POSITION_s = STARTING_POSITION_r + sizeof(TYPE_r),
STARTING_POSITION_k = STARTING_POSITION_s + sizeof(TYPE_s),
STARTING_POSITION_l = STARTING_POSITION_k + sizeof(TYPE_k),
STARTING_POSITION_m = STARTING_POSITION_l + sizeof(TYPE_l),
STARTING_POSITION_a = STARTING_POSITION_m + sizeof(TYPE_m),
STARTING_POSITION_b = STARTING_POSITION_a + sizeof(TYPE_a),
STARTING_POSITION_c = STARTING_POSITION_b + sizeof(TYPE_b),
END_POSITION = STARTING_POSITION_c + sizeof(TYPE_c),
};
std::array<unsigned char, END_POSITION> MovableBulkData;
public:
MyPodClass()
: //x(*static_cast<TYPE_x*>(&MovableBulkData[STARTING_POSITION_x])), // ERROR: Invalid type conversion. Why?
x(*(TYPE_x*)(&MovableBulkData[STARTING_POSITION_x])),
y(*(TYPE_y*)(&MovableBulkData[STARTING_POSITION_y])),
z(*(TYPE_z*)(&MovableBulkData[STARTING_POSITION_z])),
p(*(TYPE_p*)(&MovableBulkData[STARTING_POSITION_p])),
r(*(TYPE_r*)(&MovableBulkData[STARTING_POSITION_r])),
s(*(TYPE_s*)(&MovableBulkData[STARTING_POSITION_s])),
k(*(TYPE_k*)(&MovableBulkData[STARTING_POSITION_k])),
l(*(TYPE_l*)(&MovableBulkData[STARTING_POSITION_l])),
m(*(TYPE_m*)(&MovableBulkData[STARTING_POSITION_m])),
a(*(TYPE_a*)(&MovableBulkData[STARTING_POSITION_a])),
b(*(TYPE_b*)(&MovableBulkData[STARTING_POSITION_b])),
c(*(TYPE_c*)(&MovableBulkData[STARTING_POSITION_c]))
{
}
MyPodClass(MyPodClass && RValue)
: MovableBulkData(std::move(RValue.MovableBulkData)),
x(*(TYPE_x*)(&MovableBulkData[STARTING_POSITION_x])),
y(*(TYPE_y*)(&MovableBulkData[STARTING_POSITION_y])),
z(*(TYPE_z*)(&MovableBulkData[STARTING_POSITION_z])),
p(*(TYPE_p*)(&MovableBulkData[STARTING_POSITION_p])),
r(*(TYPE_r*)(&MovableBulkData[STARTING_POSITION_r])),
s(*(TYPE_s*)(&MovableBulkData[STARTING_POSITION_s])),
k(*(TYPE_k*)(&MovableBulkData[STARTING_POSITION_k])),
l(*(TYPE_l*)(&MovableBulkData[STARTING_POSITION_l])),
m(*(TYPE_m*)(&MovableBulkData[STARTING_POSITION_m])),
a(*(TYPE_a*)(&MovableBulkData[STARTING_POSITION_a])),
b(*(TYPE_b*)(&MovableBulkData[STARTING_POSITION_b])),
c(*(TYPE_c*)(&MovableBulkData[STARTING_POSITION_c]))
{
}
const MyPodClass & operator=(MyPodClass && RValue)
{
MovableBulkData = std::move(RValue.MovableBulkData);
return *this;
}
TYPE_x & x;
TYPE_y & y;
TYPE_z & z;
TYPE_p & p;
TYPE_r & r;
TYPE_s & s;
TYPE_k & k;
TYPE_l & l;
TYPE_m & m;
TYPE_a & a;
TYPE_b & b;
TYPE_c & c;
};
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
MyPodClass PodObject1, PodObject2;
PodObject1.y = 3.4;
PodObject1.s = 4;
PodObject1.m = 'm';
PodObject1.a = 2.3f;
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << "Moving PodObject1 to PodObject2..." << std::endl << std::endl;
PodObject2 = std::move(PodObject1);
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << "Modifying PodObject1 and PodObject2..." << std::endl << std::endl;
PodObject1.s = 5;
PodObject2.m = 'n';
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << std::endl;
_wsystem(L"timeout /t 60 /nobreak");
return 0;
}
Output:
PodObject1.y = 3.4
PodObject1.s = 4
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = -9.25596e+61
PodObject2.s = -858993460
PodObject2.m = ╠
PodObject2.a = -1.07374e+08
Moving PodObject1 to PodObject2...
PodObject1.y = 3.4
PodObject1.s = 4
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = 3.4
PodObject2.s = 4
PodObject2.m = m
PodObject2.a = 2.3
Modifying PodObject1 and PodObject2...
PodObject1.y = 3.4
PodObject1.s = 5
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = 3.4
PodObject2.s = 4
PodObject2.m = n
PodObject2.a = 2.3
This is a misuse of move semantics. Since your class contains a number of simple data members like int and float, there is really nothing to move. You'd be better off with memcpy(), which is probably close to what your compiler gives you for free if you just write the class the normal, naive way, with no std::array and no pointer gymnastics.
Move semantics would have been useful here if your class contained e.g. a std::string, because std::string uses dynamically allocated memory which can be "moved" (read: adopted) into the target of a move.
The above of course means that you could "fix" your problem by dynamically allocating the array, which would allow you to move it. But in the end this would be a baroque way to achieve the effect of using a trivial POD class with no gymnastics and storing it in a std::unique_ptr, which of course enables move semantics.