Posted: Mon Jul 04, 2011 3:52 pm Post subject: Arrays and Mutability
Hey guys, I'm back with another pointer question for my raytracer. I've encountered a situation where I declare a fixed array as a local variable in a function, and pass it into another function where I expect it to be modified. I've stepped through my code to make sure that the value actually *is* getting modified, but when control is returned to the original function, the value is the same. I feel like this may have something to do with a subtle difference between arrays and pointers, but I haven't found anything online to suggest that there is a problem with this. For reference, here is a dummy example of what I'm talking about:
c++:
int main() { double my_array[3];
some_function(my_array);
// after function call, my_array hasn't changed as it should have in some_function return0;
}
void some_function(double *array) { // stuff that modifies array }
While I *do* think that this is because I'm erroneously treating an array as a pointer, I would like someone who knows a thing or two about C or C++ to verify this/tell me otherwise. Thanks!
Sponsor Sponsor
crossley7
Posted: Mon Jul 04, 2011 4:07 pm Post subject: RE:Arrays and Mutability
try
c++:
void some_function (double &array) {
}
I believe you just have reference and dereference operators backwards. Check this page out to get straightened out. As it is I get confused by these regularly and avoid them if i can
Posted: Mon Jul 04, 2011 5:29 pm Post subject: RE:Arrays and Mutability
Yay pointers! I still get confused sometimes too. Remember fellas, there are 3 values associated with pointers! Their own location, the location they store and the data at the location they store.
Treating a pointer like a regular primitive type (ie no special symbols) returns the location the pointer is storing.
Any time you use an asterix, you're working with the data at the location being stored.
Any time you use an ampersand, you're working with the pointer's own location. Note this operator returns a pointer to self for all primitive types (and probably some/most/all complex types).
But you're making a raytracer, so I guess you're already aware of and practised in pointer use. I'm just writing this to prove to myself that I still know it. Also, how did I ever accomplish anything at all in Turing with no pointers (I know Turing supports pointers, but I never used them)?
apython1992
Posted: Mon Jul 04, 2011 5:39 pm Post subject: Re: RE:Arrays and Mutability
crossley7 @ Mon Jul 04, 2011 4:07 pm wrote:
try
c++:
void some_function (double &array) {
}
I believe you just have reference and dereference operators backwards. Check this page out to get straightened out. As it is I get confused by these regularly and avoid them if i can
Actually what I'm doing here with the asterisk isn't a dereference operator - this seems to be a common source of confusion amongst C/C++ programmers. Take a look at the following:
c++:
int num = 3;
int *p = #
int other_num = *p;
In this example, the first asterisk is used to declare a pointer to an int, whereas the second asterisk is used to dereference 'p" and obtain the value at the location it points to. Here, num = 3, p would be something like 0x2afc38, and other_num = 3.
All clear?
@Insectoid - this is my first time doing anything remotely serious in C++, so you can well imagine I've had my share of frustrations up to this point Not just with pointers, but with the various uses of the const keyword mingled in with class inheritance...it's been fun to say the least.
Tony
Posted: Mon Jul 04, 2011 5:52 pm Post subject: RE:Arrays and Mutability
It gets even more fun when you have const pointers. One of the interpretations might be "pointer to a constant address (can't change the value of the pointer), but data at that address is mutable". Yay C++
Posted: Mon Jul 04, 2011 6:22 pm Post subject: RE:Arrays and Mutability
Isn't that exactly what happens when you declare an array of characters in the following manner?
code:
char foo[5];
.
As far as I can tell, this is identical to the following:
code:
const char *foo = (char*) malloc (5*sizeof char)
apython1992
Posted: Mon Jul 04, 2011 6:44 pm Post subject: RE:Arrays and Mutability
Only difference is that foo in the second example would reside in memory allocated from the heap as opposed to the stack or global memory.
@Tony - I think I've seen examples of the const keyword placed after every other identifier/name in a class method:
c++:
constchar* const blah(const *value)const;
Which kinda blows my mind. I see the value in it though in terms of code-safety - things will get caught at compile time instead of tossing you a deadly little segfault your way at runtime.
Back to my original post, does anyone have any ideas?
crossley7
Posted: Mon Jul 04, 2011 7:31 pm Post subject: RE:Arrays and Mutability
I guess I learn something new in c++ every time I open it. That is part of why I almost never use pointers. I have no idea how to use them.
My only experience with them is mostly from a few tutorials and SDL surface declarations. Wish I could actually understand how they work, think I've looked at and tried to learn pointers a bunch of times
Sponsor Sponsor
Tony
Posted: Mon Jul 04, 2011 7:38 pm Post subject: RE:Arrays and Mutability
@Insectoid -- not quite, there are some C++ internals magics (aren't there always?)
Posted: Mon Jul 04, 2011 8:06 pm Post subject: RE:Arrays and Mutability
It will probably be easier if I post the two functions in question in case there is something else I am overlooking. First, here is the first function I talked about (it does nowhere near what it is supposed to yet). It declares an array called "intersect" of size 3, and then it gets passed to the object.get_intersect() method. Basically, if there is no intersection point, I just set intersect to 0 (null pointer), but that doesn't appear to ever happen back in raytrace() (like I said, I've stepped through my code to see if it actually does get set to 0 in get_intersect()).
// See if ray hits any objects, and get the closest intersection point for(unsignedint i = 0; i < objects.size(); i++) {
objects[i]->get_intersect(ray, intersect);
if(intersect == 0)continue;
curr_mag = sqr_mag(intersect);
if(i == 0) {
min_mag = sqr_mag(intersect); // Origin is (0, 0, 0) so we don't need vector subtraction here
min_intersect = intersect;
} elseif(curr_mag < min_mag) {
min_mag = curr_mag;
min_intersect = intersect;
} }
// Take magnitude of line drawn from calculated point to center // of sphere; if greater than radius, no intersect, if equal, return // calculated point, else carry out final calculation double mag = sqr_mag(center_to_ray);
if(mag <= EPSILON) {
tc -= m_radius;
for(int i = 0; i <= 2; i++)
intersect[i] = tc * ray_direction[i] + ray_origin[i];
} elseif(mag > m_radius) {
intersect = 0;
} else { // Use Pythagorean Theorem to calculate closest point based on right triangle double tf = tc - sqrt(m_radius - mag);
for(int i = 0; i <= 2; i++)
intersect[i] = tf * ray_direction[i] + ray_origin[i];
} }
DemonWasp
Posted: Tue Jul 05, 2011 8:04 am Post subject: RE:Arrays and Mutability
I'm pretty sure your array is getting passed by value, which means copying. If you print out the value of "&intersect" just before the call to get_intersect() and just inside that function, you'll find that they're different (if I'm correct).
What you probably want is for your method signature to look like:
c++:
void Sphere::get_intersect(const Ray *ray, double ** intersect)const
Note the two stars -- it's a pointer to an array, so one star for pointer, one for array.
Then your method call looks like:
c++:
objects[i]->get_intersect(ray, &intersect);
Note the & operator being used to get the address of intersect so you can pass a pointer by value.
Now, I'm not a C++ expert and I haven't tried this right this moment, so I could be totally wrong. You should probably try this on your trivial example first. There may also be a "neater" way of doing it, but I wouldn't know.
apython1992
Posted: Tue Jul 05, 2011 8:45 am Post subject: Re: RE:Arrays and Mutability
DemonWasp @ Tue Jul 05, 2011 8:04 am wrote:
I'm pretty sure your array is getting passed by value, which means copying. If you print out the value of "&intersect" just before the call to get_intersect() and just inside that function, you'll find that they're different (if I'm correct).
Passing an array into a function will pass a pointer to its first element. I have verified that my array *is* getting passed by reference (a pointer to the first element of the array is passed, by value). I think I have found my problem, though: In get_intersect, if there is no intersection point I am trying to change the pointer's address in memory (pointing to NULL), which I believe is strictly forbidden with arrays, because they are essentially constant pointers. I'm finding myself getting thoroughly surprised by the behaviour of g++ - it sure isn't picking up a lot of these mis-uses (though to be fair, I'm only compiling using the default settings in Code::Blocks, so I should probably add some flags to help me catch some of this stuff).
All this being said - is there an easy way to get array-like behaviour on the stack without having to treat is as a const pointer? If not, I can find another mechanism for handling non-intersections, but I may as well learn something.
Appreciate the help guys.
apython1992
Posted: Tue Jul 05, 2011 9:05 am Post subject: Re: RE:Arrays and Mutability
Insectoid @ Mon Jul 04, 2011 6:22 pm wrote:
Isn't that exactly what happens when you declare an array of characters in the following manner?
code:
char foo[5];
.
As far as I can tell, this is identical to the following:
code:
const char *foo = (char*) malloc (5*sizeof char)
Also I think this is a pointer which points to values that are const. Instead, we'd want a constant pointer with mutable values. It would have to be
I think that syntactically it should be the other way around. Makes more sense to me.
DemonWasp
Posted: Tue Jul 05, 2011 9:37 am Post subject: RE:Arrays and Mutability
Part of the value of stack allocation is the assurance that the value is non-nullable (see RAII). You should probably just return a boolean indicating intersection or non-intersection.
apython1992
Posted: Tue Jul 05, 2011 9:43 am Post subject: RE:Arrays and Mutability
I do need the actual point of intersection though (because it will be the origin for subsequent rays). I kept everything stack-based and just changed it to set the z co-ordinate of the intersection to -1 if it misses (this would ever happen with the way my raytracer is set up. A bit of a hackish solution, but it'll work).