what is the correct Pointer to members definition? [duplicate] - c++

This question already has answers here:
Pointer to class data member "::*"
(18 answers)
Closed 3 months ago.
i took the below code from a different question on stackoverflow, im not sure What do the lines int (Foo :: * ptr); and int (Foo :: * ptr) (); mean? Can anyone share some answers?
struct Foo {
int a;
int b;
};
int main ()
{
Foo foo;
int (Foo :: * ptr);
ptr = & Foo :: a;
foo .*ptr = 123; // foo.a = 123;
ptr = & Foo :: b;
foo .*ptr = 234; // foo.b = 234;
}
Member functions are almost the same.
struct Foo {
int a ();
int b ();
};
int main ()
{
Foo foo;
int (Foo :: * ptr) ();
ptr = & Foo :: a;
(foo .*ptr) (); // foo.a ();
ptr = & Foo :: b;
(foo .*ptr) (); // foo.b ();
}
Debugging to no avail

Pointer to members is a long story to tell. First we assume that you've known what a normal pointer is.
Pointer to members suggests that it can point to the specific member of any instance of class. There are two types of pointer to members, first to member variables and second to member functions.
Before that, the variables and functions can be static or non-static. For static ones, it's no other than normal global ones from the program's perspective, e.g. in Linux ELF, static data are stored in .data directly, where the global variables are also stored. From the angle of the programmers, they are just accessing a special global function / variable as well, just adding some Class::. So, the pointer to static member variable / function is just the same as the pointer to a normal variable / function.
Now let's talk about the non-static ones. Non-static members should always bind to some specific object, e.g. obj.a or obj.func() and Class::a or Class::func() is illegal. Then, is it possible to use a pointer to suggest that "I hope to point to a specific member of any instance, and when I want to use it, I will bind an instance"? That's what the pointer to members do.
Wait... you may think: "That bothers! Why can't I just use the .?". To maintain the consistency, we will go back to this question finally. Now we assume it's useful first, and see what syntax it uses.
class ClassOpTest
{
public:
int nsVar; // non-static variable.
void nsFunc(int){return;} // non-static function.
};
int ClassOpTest::* nsVarPtr = &ClassOpTest::nsVar;
void (ClassOpTest::*nsFuncPtr)(int) = &ClassOpTest::nsFunc;
int main()
{
ClassOpTest object2;
ClassOpTest* object2Ptr = &object2;
object.*nsVarPtr = 1; // equals to object.nsVar = 1;
object2.*nsVarPtr = 2; // equals to object2.nsVar = 2;
object2Ptr->*nsVarPtr = 3; // equals to object2.nsVar = 3;
// Note that these paratheses are necessary, considering the operation order.
// If there are not, nsFuncPtr() will be resolved first rather than object.*nsFuncPtr().
// That is, the compiler will regard the nsFuncPtr as a normal function (pointer)
// rather than pointer to member function, so "obj.*" is just a meaningless mess.
// All in all, no paratheses will cause compilation error.
(object.*nsFuncPtr)(1); // equals to object.nsFunc(1);
(object2Ptr->*nsFuncPtr)(2); // equals to object2.nsFunc(2);
return 0;
}
You may find it's troublesome to write types like this, so you can use deduced type in C++11 as:
using ClassOpTestIntPtr = decltype(&ClassOpTest::nsVar);
using ClassOpTestFuncPtr = decltype(&ClassOpTest::nsFunc);
ClassOpTestIntPtr nsVarPtr = &ClassOpTest::nsVar;
ClassOpTestFuncPtr nsFuncPtr = &ClassOpTest::nsFunc;
Notice that the decltype doesn't mean it always points to nsVar or nsFunc; it means the type same as them.
You may also think .* or ->* is oblique(me too!), then you can use std::invoke in C++17 like this :
std::invoke(nsVarPtr, object2) = 1; // equals to object.*nsVarPtr = 1;
std::invoke(nsVarPtr, &object2) = 2; // equals to object2Ptr->*nsVarPtr = 2;
// both work.
std::invoke(nsFuncPtr, object2, 1); // equals to (object.*nsFunc)(1);
std::invoke(nsFuncPtr, &object2, 2); // equals to (object2Ptr->*nsFunc)(2);
std::invoke is significantly useful, but that's not the point of the answer. In a nutshell, it will use corresponding operator when the second calling parameter varies.
Finally, why is it useful? In my point of view, that's mostly because the pointer only conveys the type, and the type may infer lots of members. For instance:
struct RGB
{
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
};
and I hope to blend two std::vector<RGB> using Intel's SIMD intrinsics. First for r, that is:
reg1 = _mm_set_epi16(RGBdata1[i + 7].r, RGBdata1[i + 6].r, RGBdata1[i + 5].r,
RGBdata1[i + 4].r, RGBdata1[i + 3].r, RGBdata1[i + 2].r,
RGBdata1[i + 1].r, RGBdata1[i].r);
reg2 = _mm_set_epi16(RGBdata2[i + 7].r, RGBdata2[i + 6].r, RGBdata2[i + 5].r,
RGBdata2[i + 4].r, RGBdata2[i + 3].r, RGBdata2[i + 2].r,
RGBdata2[i + 1].r, RGBdata2[i].r);
reg1 = _mm_mullo_epi16(reg1, alphaReg1);
reg2 = _mm_mullo_epi16(reg2, alphaReg2);
resultReg1 = _mm_add_epi16(reg1, reg2);
// for simplicity, code below omitted; there are also manys operation to get the result.
// ...
// store back
_mm_store_si128((__m128i*)buffer, resultReg1);
for(int k = 0; k < 16; k++)
{
outRGBdata[i + k].r = buffer[k];
}
So what about g and b? Oops, okay, you have to paste the code twice. What if you find some bugs and want to change something? You have to paste again for g and b. That suffers! If we use pointer to members, then :
using RGBColorPtr = std::uint8_t RGB::*;
void SIMDBlendColor(RGB* begin1, RGB* begin2,
RGB* outBegin, RGBColorPtr color,
__m128i alphaReg1, __m128i alphaReg2)
{
__m128i resultReg1, reg1, reg2;
alignas(16) std::uint8_t buffer[16];
reg1 = _mm_set_epi16((begin1 + 7)->*color, (begin1 + 6)->*color,
(begin1 + 5)->*color, (begin1 + 4)->*color,
(begin1 + 3)->*color, (begin1 + 2)->*color,
(begin1 + 1)->*color, begin1->*color);
reg2 = _mm_set_epi16((begin2 + 7)->*color, (begin2 + 6)->*color,
(begin2 + 5)->*color, (begin2 + 4)->*color,
(begin2 + 3)->*color, (begin2 + 2)->*color,
(begin2 + 1)->*color, begin2->*color);
reg1 = _mm_mullo_epi16(reg1, alphaReg1);
reg2 = _mm_mullo_epi16(reg2, alphaReg2);
resultReg1 = _mm_add_epi16(reg1, reg2);
// ...
_mm_store_si128((__m128i*)buffer, resultReg1);
for(int k = 0; k < 16; k++)
{
(outBegin + k)->*color = buffer[k];
}
return;
}
Then, you can just call like this :
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::r, alphaReg1, alphaReg2);
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::g, alphaReg1, alphaReg2);
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::b, alphaReg1, alphaReg2);
Clean and beautiful!
BTW, I strongly recommend you to check iso-cpp-wiki for more information.

Related

How do I reuse my hasher in another hasher?

I have been given a task to write a C++ program that stores an unordered_set of objects street. At the same time, object street is to contain some general info and an unordered_set of objects house. I have written a structure-hasher for house
struct house_hasher {
std::hash<std::string> number_hash;
std::hash<size_t> storeys_hash;
std::hash<size_t> aparts_hash;
std::hash<size_t> residents_hash;
std::hash<std::string> street_name_hash;
std::hash<double> pfsm_hash;
std::hash<double*> pea_hash;
std::hash<double*> sea_hash;
std::hash<bool*> ps_hash;
size_t operator()(const house& h) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
hash_value = (pow(coef, 8) * number_hash(h.getter_number()) +
pow(coef, 7) * storeys_hash(h.getter_storeys_n()) +
pow(coef, 6) * aparts_hash(h.getter_aparts_n()) +
pow(coef, 5) * residents_hash(h.getter_residents_n()) +
pow(coef, 4) * street_name_hash(h.getter_street_name()) +
pow(coef, 3) * pfsm_hash(h.getter_price_for_square_meter()) +
pow(coef, 2) * pea_hash(h.getter_payments_each_apartments()) +
coef * sea_hash(h.getter_square_each_apartments()) +
ps_hash(h.getter_payments_statuses()));
return hash_value;
}
};
to enable adding house to the container and it works correctly. But the thing is that I have to write a structure-hasher for object street since it must be addable as well. I assume I could easily add another structure and copy-paste the code from the initial structure to the one mentioned, so that the part, that hashes houses, repeats twice in the project but still it seems to be stupid.
What I want to do is to create one more structure-hasher for streets but to use the object of house_hasher in it and be able to hash houses like that
struct street_hasher {
std::hash<std::string> name_hash;
std::hash<size_t> number_hash;
std::hash<size_t> houses_hash;
std::hash<std::unordered_set<house, house_hasher>> uset_houses_hash;
size_t operator()(const street& s) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
size_t add_hash = 0;
house_hasher hasher_for_house;
std::unordered_set<house, house_hasher>::iterator uset_it = s.getter_street_uset_houses().begin();
for (uset_it; uset_it != s.getter_street_uset_houses().end(); ++uset_it) {
add_hash += hasher_for_house(*uset_it);
}
hash_value = (pow(coef, 3) * name_hash(s.getter_street_name()) +
pow(coef, 2) * number_hash(s.getter_street_number()) +
coef * houses_hash(s.getter_street_houses_n()) +
add_hash);
return hash_value;
}
};
However, this does not seem to be correct. VS throws an error C2280 "std::_Uhash_compare<_Kty,_Hasher,_Keyeq>::_Uhash_compare(const std::_Uhash_compare<_Kty,_Hasher,_Keyeq> &)": предпринята попытка ссылки на удаленную функцию
The last few words say an attempt to refer to deleted function occurred.
I have tried a lot of ideas of mine and those found on the net. Still, there is no output. Could anybody please tell me how to solve this tricky problem?
Thanks in advance!
The solution is to arrange the street_hasher structure this way (it works but I am sure there is another way to make this work which would be more elegant and laconic):
struct street_hasher {
std::hash<std::string> name_hash;
std::hash<size_t> number_hash;
std::hash<size_t> houses_hash;
size_t operator()(const street& s) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
size_t add_hash = 0;
house_hasher hasher_for_house; // need this to hash houses
std::unordered_set < house, house_hasher > uset = s.getter_street_uset_houses();
std::unordered_set<house, house_hasher>::iterator uset_it = uset.begin();
std::unordered_set<house, house_hasher>::iterator end_it = uset.end();
size_t houses_it = s.getter_street_houses_n() + 2;
// there is 2 as we have y = 3 more attributes to hash in street
// but we start with the power of n - 1, where n = houses_n + y =>
// => n = s.getter_street_houses_n() + 3
// => n - 1 = s.getter_street_houses_n() + 2
hash_value = (pow(coef, houses_it) * name_hash(s.getter_street_name()) +
pow(coef, houses_it - 1) * number_hash(s.getter_street_number()) +
pow(coef, houses_it - 2) * houses_hash(s.getter_street_houses_n()) +
add_hash);
houses_it -= 3;
for (uset_it; uset_it != end_it; ++uset_it) {
add_hash += pow(coef, houses_it) * hasher_for_house(*uset_it);
--houses_it;
}
// I guess it is much safer to treat each house as an independent attribute
hash_value += add_hash;
return hash_value;
}
};
I have deleted std::hash<std::unordered_set<house, house_hasher>> uset_houses_hash; from the header and it stopped throwing the error. After one problem went away, another one came. The compiler was angry at how I initialized the loop saying list iterators incompatible. I have just rearranged the function a bit by setting so-called static house_hasher and iterators. As an addition, I came up with a thought to deal with each house in unordered_set as with a different attribute of street, so that we avoid collisions (I may have just said something stupid but still let it be this way). Thus, such way of hashing seems to me say more safer. Anyway, it works!
Cheers!

use of 'n' before deduction of 'auto' C++

I'm trying to have my function return 3 values (n, down and across) I've read online how 'auto' can be used but must be doing something wrong.
The function takes in a 2D vector of integers (as well as other variables) and checks for how many numbers are connected to board[0][0] such that they are the same number.
I've tried putting auto in front of the function inside the function itself, tried leaving it blank, tried just having chain = chainNodes(...) but I always seem to get an error. Here's the code:
tuple<int, int, int> chainNodes(vector<vector<int>> board, int originalNum,
unsigned int across, unsigned int down, int ijSum,
int n)
{
struct chain {
int n, down, across;
};
if(down + across > ijSum) {
ijSum = down + across;
} else if((down + across == ijSum) &&
((down - across) * (down - across) < (ijSum) * (ijSum))) {
ijSum = down + across;
}
board[down][across] = 0;
n += 1;
// Check below
if((down != (board.size() - 1)) && (board[down + 1][across]) == originalNum) {
down += 1;
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
down -= 1;
}
// Check right, up and left (I've removed so its not too messy here)
return chain{n, down, across};
}
Sorry, I forgot to include the error message.
error: use of 'n' before deduction of 'auto'
It occurs on the line that uses auto.
Issue with
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
is similar to
auto n = foo(n); // `foo(n)` uses `n` from `auto n`,
// not the one from outer scope as function parameter
The construct int a = a + 1; is legal but lead to UB as reading uninitialized variable.
That kind of construct allows legal and valid behavior void* p = &p;.
Your code has other errors and it is not clear for me expected behavior of the function.
So not sure if following is the correct fix, but you might want:
n = std::get<0>(chainNodes(board, originalNum, across, down, ijSum, n));

Allocating the correct size of struct variable with sub-structs

So I am trying to allocate the correct size for a variable. Then copy another variable to this new one and later access the new variable's data.
Structs:
struct Validations {
int validationId;
int count; // total queries
char queries[];
};
struct Query {
struct Column {
enum Op : int { Equal, NotEqual };
int column;
int value;
Op op;
};
int relationId;
int columnCount; // total columns
Column columns[];
};
Code:
// function that creates the new val
void function1(Validations* val){
int size = sizeof(Validations) + val->count;
Validations *new_val = (Validations*)malloc(size);
memcpy(new_val, val, size);
// I store this val in a global list
}
void function2(){
// I pop the val here
// I am casting here in order to get the values that i want
const char* reader = popped_val->queries;
for (...){
// casting again
const Query* q = (Query*)reader;
// operations....
// SIGSEGV here after reader is incremented and q is casted again
// done with operations, go to next
reader += sizeof(Query)+(sizeof(Query::Column)*q->columnCount);
}
}
The problem is that the new_val size that I am allocating in the first function is probably not the right one because I get a segmentation fault after the second cast of the function2 after trying to access the data.
What I tried:
1) size = 1000; Tried that for testing and it worked so the problem is surely the size.
2) size = sizeof(Validations) + val->count * sizeof(Query) * sizeof(Query::Column) * q->columnCount;. This one looks like the correct one to me but it does not work.
The correct expression should be more like this:
size = val->count * (sizeof(Validations) + sizeof(Query) + (sizeof(Query::Column) * q->columnCount));
But note that you probably have to add up the column counts for each individual Query if they can vary.

Access violation, cant figure out the reason

So, been building this class:
public class BitArray {
public:
unsigned char* Data;
UInt64 BitLen;
UInt64 ByteLen;
private:
void SetLen(UInt64 BitLen) {
this->BitLen = BitLen;
ByteLen = (BitLen + 7) / 8;
Data = new unsigned char(ByteLen + 1);
Data[ByteLen] = 0;
}
public:
BitArray(UInt64 BitLen) {
SetLen(BitLen);
}
BitArray(unsigned char* Data, UInt64 BitLen) {
SetLen(BitLen);
memcpy(this->Data, Data, ByteLen);
}
unsigned char GetByte(UInt64 BitStart) {
UInt64 ByteStart = BitStart / 8;
unsigned char BitsLow = (BitStart - ByteStart * 8);
unsigned char BitsHigh = 8 - BitsLow;
unsigned char high = (Data[ByteStart] & ((1 << BitsHigh) - 1)) << BitsLow;
unsigned char low = (Data[ByteStart + 1] >> BitsHigh) & ((1 << BitsLow) - 1);
return high | low;
}
BitArray* SubArray(UInt64 BitStart, UInt64 BitLen) {
BitArray* ret = new BitArray(BitLen);
UInt64 rc = 0;
for (UInt64 i = BitStart; i < BitLen; i += 8) {
ret->Data[rc] = GetByte(i);
rc++;
}
Data[rc - 1] ^= (1 << (BitLen - ret->ByteLen * 8)) - 1;
return ret;
}
};
just finished writing the SubArray function and went on to test but I get "Access violation: attempted to read protected memory" on the line where GetByte(i) gets called. I tested a bit and it doesn't seem to have anything to do with the data array or i, placing "int derp = GetByte(0)" on the first line of the function produces the same error.
calling GetByte from outside the class works fine, I don't understand whats going on.
the test function looks like this:
unsigned char test[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
BitArray* juku = new BitArray(test, 64);
auto banana = juku->GetByte(7); //this works fine
auto pie = juku->SubArray(7, 8);
You might want to consider creating an array of characters, changing:
Data = new unsigned char(ByteLen + 1);
into:
Data = new unsigned char[ByteLen + 1];
In the former, the value inside the parentheses is not the desired length, it's the value that *Data gets initialised to. If you use 65 (in an ASCII system), the first character becomes A.
Having said that, C++ already has a pretty efficient std::bitset for exactly the situation you seem to be in. If your intent is to learn how to make classes, by all means write your own. However, if you want to just make your life simple, you may want to consider using the facilities already provided rather than rolling your own.

How macros with loop actually work in C/C++

This is a piece of code that i directly took from CImg library trying to understand how it actually works inside
Macro is defined in line 628 as
#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
and CImg has a constructor called like this in line number 9035
template<typename t>
CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {
if (is_shared) {
_width = _height = _depth = _spectrum = 0; _data = 0;
throw CImgArgumentException(_cimg_instance
"CImg() : Invalid construction request of a (%u,%u,%u,%u) shared instance from a (%s*) buffer "
"(pixel types are different).",
cimg_instance,
size_x,size_y,size_z,size_c,CImg<t>::pixel_type());
}
const unsigned int siz = size_x*size_y*size_z*size_c;
if (values && siz) {
_width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
try { _data = new T[siz]; } catch (...) {
_width = _height = _depth = _spectrum = 0; _data = 0;
throw CImgInstanceException(_cimg_instance
"CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
cimg_instance,
cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
}
const t *ptrs = values + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
} else { _width = _height = _depth = _spectrum = 0; _data = 0; }
}
I believe this is how macro will be used, but would like a second opinion
for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
*ptrd = (T)*(--ptrs);
the entire confusion is because of two ptrs variable
The preprocessor doesn't know C. It operates on tokens. for is a token like rof, as far as the preprocessor knows.
So, the bit that follows the macro? The preprocessor doesn't know that's part of a for statement. Once it's seen the closing ) of cimg_for(, it's done. No further replacements.
In your case, cimg_for(*this,ptrd,T) sets:
img to this
ptrs to ptrd
T_ptrs to T (Type of ptrs)
This code is weird, BTW: If you have C++, you don't need these macro hacks.
This doesn't look like C, but here's how macros work in C:
Macro keyword is searched throughout the code. Macro keyword is replaced with its definition prior to compilation. If it is a macro with arguments, the passed arguments are replaced with the ones inside the definition.
In your case, the:
cimg_for(*this,ptrd,T)
Will be turned into the following:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
While writing that, I have first copied the definition, then replaced each img inside definition with *this, then replaced each ptrs with ptrd, and lastly each T_ptrd with T. That's what macro definition told me to do, that's also what preprocessor does prior to compilation.
After that macro thing, there is a statement, so in the end, the loop looks like the following:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
*ptrd = (T)*(--ptrs);
Macros aren't functions. They are basically an elaborate "search and replace". The preprocessor literally replaces where ever it finds the macro (within the scope that the macro is declared) with the body of the macro.
Some gatchas: Because macros are not like functions, things like this become dangerous
#define SQUARE(A) A*A
int i = 2;
int j = SQUARE(++i);
k == 9 // oops!
or this
int i = SQUARE(IncrediblyExpensiveFuncionThatReturnsAnInt());
That huge function gets called twice. Once for each A in the macro
For more info on the dangers of macros and how they work, check out this
This
#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
becomes
for (T *ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
*ptrd = (T)*(--ptrs);