简体   繁体   中英

Understanding C++ operator overloading

I was reading the source of a hashing competition today, and came across this:

#define BYTES_IN_BLOCK 1024

struct block{
    uint8_t v[BYTES_IN_BLOCK];

    block(){ memset(v, 0, BYTES_IN_BLOCK); }
    uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
};

Then, a little later in the code, there's this:

state = new block[cost]; // cost is a uint32_t (like 1024)
// Probably 50 lines of code.
block prev_block;

prev_block = state[foo]; // foo is a uint32_t

What I can't figure out is what this is doing. Now, I understand C, but C++ not so much. Bear with me here for a second.

This part: return *(uint64_t*)(v+8*i) should return a uint64_t , and does so when I tested it:

state->v[8*10] = 12;
uint64_t bar = *(uint64_t*)(v+8*10);
printf("%" PRIu64 "\n", bar);

So that all makes sense.

But this:

prev_block = state[foo];

Makes no sense. Since state is block* , prev_block should now "be" state , correct? But it doesn't, because their arrays are different.

state->v[8*12] = 12;
printf("%" PRIu64 "\n", (*state)[12]);
prev_block = state[12];
printf("%" PRIu64 "\n", (*(&prev_block))[12]);

So, what exactly is going on here?

state = new block[cost];
prev_block = state[foo];

is analogous to:

int* arr = new int[size];
int a = arr[index];

That's basic C++. I am not sure why that is confusing.

You are mixing up the two operator[] s involved here. In your last example, you set state[0][12] = 12 , and you're comparing it to state[12][12] . Since state is a block* , state[n] is just normal array access; it doesn't invoke the operator[] defined in block .

There is confusion with a number of concepts here. I'm going to blast through all the ones I see because they are all important, not just the immediate answer.

state is a pointer to block, but state[0] should just be a block, specifically the first block in state and also the result of *state .

prev_block = state[foo];

All of the data in block is simple, just a self-contained array of bytes, so it should be directly copy-able without any special assistance. prev_block = state[foo] should copy state[foo] to prev_block. Since it's a copy, the addressing will be different.

In the printout code provided:

state->v[8*12] = 12;

Breaking his down for clarity. state-> is going to access the first element of the state array. state->v[8*12] is going to access v[8*12] of state[0]. state->v[8*12] = 12; is going to set v[8*12] of state[0]to 12. This means byte 96 of v is going to be 12. To reference a different state you can use (state + array_index)->v[8*12]; or state[array_index].v[8*12]; I find the latter more readable.

printf("%" PRIu64 "\n", (*state)[12]);

(*state) gives you the first state in the array, AKA state[0] . (*state)[12] uses state[0] 's [] operator, defined as uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); } uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }

This is going to return a 64 bit int starting at the address of state[0].v[12*8] and comprised of the next 8 bytes of array v (v[96] through v[103], resulting in 12,0,0,0,0,0,0,0). This will be 12 or a god-awful big number depending on the system's endian . The wrapping printf is going to print the returned number.

prev_block = state[12];

Is going to copy the 13th element of the state array to prev_block, assuming enough blocks were created by state = new block[cost]; . Nothing magical, but there shouldn't be anything there but zeros because the only state that has any values set is state[0]. You either wanted to copy state[0] here or write to state[12] up a few lines.

printf("%" PRIu64 "\n", (*(&prev_block))[12]);

the * and & cancel each other out before accomplishing anything. It will then print out the result of using the block [] operator as above. Should be zero.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM