I'm reading this tutorial on computer graphics, and ran across the following code example.
template<typename T>
class Vec3
{
public:
// 3 most basic ways of initializing a vector
Vec3() : x(T(0)), y(T(0)), z(T(0)) {}
Vec3(const T &xx) : x(xx), y(xx), z(xx) {}
Vec3(T xx, T yy, T zz) : x(xx), y(yy), z(zz) {}
T x, y, z;
};
typedef Vec3<float> Vec3f;
Vec3<float> a;
Vec3f b;
I recognize that each constructor is making use of member initializer lists.
The default constructor initializes x, y, and z as 0 of type T
?
The constructor accepts x, y, and z explicility and initializes the member variables accordingly.
I'm not sure what 2. is trying to illustrate, or how I would use it. What does const T &xx mean exactly? I get that xx is a pointer to some variable of type T, but is the const referring to the pointer itself or the variable it's pointing to? Furthermore, what's the point of initializing x, y, and z with the same variable?
const T &xx is a reference (&) to a const T.
By using a reference instead of simply passing T xx, a potentially expensive copy can be avoided, in case T is a complex type. (Might be premature optimization in this case, because your typical Vec3 will only be instantiated with types like float or double, but the compiler will optimize it out anyway.)
By making it a reference to a const T, the caller can be certain that the T they pass in will not be modified by the constructor. Moreover, the caller will be able to pass values that are already const, like literals (e.g. Vec3<double>(1.0)).
The rule with const is: it always refers to the thing that precedes it. So int const *x means that x is a (mutable) pointer to a const int, whereas int *const x means that x is a const pointer to a (mutable) int. int const *const x is also possible.
But what if the const is the first token in the type, so there's nothing that precedes it? Then it "jumps over one", so const T &xx is the same as T const &xx. For consistency, I prefer to write the latter, but many people use the former because it reads more naturally from left to right.
This constructor would be useful if you want a vector set to (1, 1, 1), for instance. Of questionable mathematical meaning, but sometimes useful. For example, by multiplying a vector (x, y, z) by (1, 1, 1) we can easily compute the sum of the components of the former vector.
Related
I am translating a java program to C++, and the architecture requires me to return a null pointer at certain points.
I have a pointer constructed as such:
auto p= std::make_unique< std::array< A, 3>>();
where A is of the form:
class A
{
public:
double x = 0, y = 0;
A(const double x, const double y):
x(x), y(y)
{}
};
Now, I would need to set the members through the pointer, so I would think:
p[0].x += 1.0;
Since unique_ptr has the dereferencing [] operator, but that fails with:
error: no match for 'operator[]' (operand types are 'std::unique_ptr<std::array<A, 3ull> >' and 'int')
I reviewed similar questions, but it is unclear to me if what I want to do is possible. Is the [] operator for c-style declared arrays only?
Is the [] operator for c-style declared arrays only?
Yes, it's only supported for the array version, i.e. unique_ptr<T[]>, std::array is not counted.
You can use operator* instead, like
(*p)[0].x += 1.0;
I have been looking through source code trying to learn more about C++ and I came across some code that looked confusing. I haven't been able to figure out its use by playing around with it.
Please can someone explain what the operator float *() does and how it is used?
class Vector
{
public:
float x,y,z;
Vector() : x(0), y(0), z(0){
}
Vector( float x, float y, float z ) : x(x), y(y), z(z){
}
operator float*(){
return &x;
}
operator const float *(){
return &x;
}
I have searched StackOverflow and it looks like it is a conversion operator but I am still unsure what it actually does and why it is useful.
Kind regards,
operator type_name declares an implicit conversion operator. In other words, this function is called when you are attempting to (implicitly) convert an object of your type to float* – for instance in an assignment:
Vector x(1, 2, 3);
float* f = x;
assert(*f == 1);
Needless to say, this particular conversion is quite terrible because its effect is pretty unintuitive and easily results in impossible to find bugs. Implicit conversions should generally be handled with care since they hide potentially confusing semantics. But they can be used well with types which are supposed to be used interchangeably, and where a conversion doesn’t hurt.
For instance, consider the case where you write your own integer and complex classes. A conversion from integer to complex is harmless, since every integer is a complex number (but not vice-versa). So having an implicit conversion integer → complex is safe.
As it was said it is a conversion operator that converts an object of type Vector to an object of type float *. This conversion operator can be called implicitly because it has no function specifier explicit.
I think that the idea of introducing this operator was to access data members x, y, z as an array of floats. In this case you could apply some standard algorithms to an object of the class converting it to an array of floats.
Take into account that the second overloaded operator-function shall have qualifier const.
Consider the following code
#include <iostream>
#include <algorithm>
class Vector
{
public:
float x,y,z;
Vector() : x(0), y(0), z(0){
}
Vector( float x, float y, float z ) : x(x), y(y), z(z){
}
operator float*(){
return &x;
}
operator const float *() const {
return &x;
}
};
int main()
{
Vector v( 1, 3, 2 );
auto max = std::max_element( v + 0, v + 3 );
std::cout << *max << std::endl;
return 0;
}
The output is 3.
Take into account that according to the C++ Standard
13 Nonstatic data members of a (non-union) class with the same access
control (Clause 11) are allocated so that later members have higher
addresses within a class object
So the order of the data members of the class is defined.
It's a conversion operator allowing the class to be used with APIs that want a float*.You have two different versions because one will convert the class to a const float* and the other to a non-const. The non-const conversion operator breaks your class's encapsulation though.
Usefulness: Well it can be very handy when, as I mentioned, you want to work with a library that expects a certain type. It can also be useful when there is a natural conversion between two types.
The following code compiles fine. However I wonder if it is legal C++. So more specific, if I have a const object, am I allowed to modify variables through pointers/references of that object?
class Foo {
public:
int* a;
int& b;
Foo(int* _a, int& _b) : a(_a), b(_b) {}
};
int main ( int argc, char* argv[] ) {
int x = 7;
const Foo bar(&x, x);
*bar.a = 3; //Leagal?
bar.b = 7; //Legal?
return 0;
}
It's legal, as const-ness of the class means that the class member is constant. a is a pointer, so the address the pointer points to is constant, but the value stored at that address need not be.
Hence bar.a is effectively an int * const, not an int const *.
As, after initialization, a reference cannot be made to refer to another entity anyway, it does not matter for bar.b whether bar is declared const or not.
The constant variant of a pointer is a constant pointer, not a pointer to a constant. The constant variant of a reference is a reference, not a reference to a constant.
Small digression: You should be careful with references as members anyway in connection with const-ness, as the following will probably compile
struct Y { int m_a; };
struct X {
const Y & m_y;
X (const Y & y) : m_y (y) { }
};
Y y;
y.m_a = 1;
X x (y); // or const X x (y) -- does not matter
// X.m_y.m_a == 1
y.m_a = 2;
// now X.m_y.m_a == 2, although X.m_y is supposed to be const
As it is possible to assign a pointer to non-const to a pointer to const, you can build an analogous example with pointers. Remember that const does only guarantee that YOU will not modify a variable via this very variable, it cannot guarantee that the contents of the variable are not modified at all.
I find the best way to think about const in C++ is that it protects the physical bits of the object. It has no real protection for objects that it refers to. You can control the object definition with const methods to provide deeper protection of values but by default C++ really only protects the physical object itself
One of the reasons why C++ allows you to modify the contents of a pointer through a const value is that it really can't stop you. Imagine for a second that C++ disallowed that particular construct. You could trivially violate it by doing the following
size_t t1 = (size_t)bar.a; // legal
int* t2 = (int*)t1; // legal
*t2 = 3; // exactly the same as *bar.a = 3
As part of an assignment we have been asked to create a Vector3D class which uses memory allocated on the Heap. I have a Vector3DHeap class with the following constructor.
Vector3DHeap::Vector3DHeap(float& x, float& y, float& z)
{
this->x = &x;
this->y = &y;
this->z = &z;
}
If I want to get a unit vector, I was expecting the be able to do the following. This gives the error message "No instance of constructor matches the argument list, argument types are (float, float, float).
Vector3DHeap* Vector3DHeap::getUnitVector()
{
float m = *getMagnitude();
return new Vector3DHeap((*x / m), (*y / m), (*z / m));
}
The compiler is happy if I define three float variables, a, b and c and pass these to the constructor. What is wrong with the code above?
Vector3DHeap* Vector3DHeap::getUnitVector()
{
float m = *getMagnitude();
float a, b, c;
a = *x / m;
b = *y / m;
c = *z / m;
return new Vector3DHeap(a, b, c);
}
Many thanks,
George
Your problem with the first version is that your compiler is trying to prevent a bug.
Your problem with the second version is that you outsmarted your compiler and successfully managed to create a bug.
Given your constructor, you want to store pointers to the float values that are passed by reference. Since your second version now calls the constructor with references to the local variables float a, b, c;, you created an instance of Vector3DHeap which references them. But as soon as getUnitVector returns, those variables no longer exist and the references stored in Vector3DHeap became dangling references.
The solution is not to store pointers inside Vector3DHeap or to create copies of the parameters:
Vector3DHeap::Vector3DHeap(float x, float y, float z)
{
this->x = new float(x);
this->y = new float(y);
this->z = new float(z);
}
Make sure that you properly delete the stored floats, though.
It is good that the compiler stopped you from binding a reference to a temporary because otherwise you would have ended up with an object pointing to already destroyed objects: The expressions *x / m and similar each yield a temporary float object which will disappear at the end of the expression. Trying to bind a temporary to a non-const reference will fail.
However, I doubt that you really want to do any of that: you shouldn't use pointers unless you really know that you need to use pointers! Your constructor should probably rather look like this:
Vector3DHeap::Vector3DHeap(float x, float y, float z)
: x(x), y(y), z(z) {
}
where the members are, of course, also of type float. getMagnitude() should return a float, too. ... as should getUnitVector() return a Vector3DHeap rather than a pointer to it!
(*x / m) is a temporary object.
Vector3DHeap(float& x, float& y, float& z) requires a non-const reference as first parameter.
You can't pass a temporary object to a function that expects a non-const reference. See https://stackoverflow.com/questions/13826897#13827042 for details why C++ does not want to allow this.
I want to write a generic function that takes a reference x and a value y, and if y is greater than x assigns x to y. (performance critical)
Here is what I have:
template<class X, class Y>
inline void chmax(X& x, const Y& y) { if (y > x) x = y; }
Is this the best way?
I am concerned about the parameter type "const Y&", what would be the difference if I made it just "Y"? Will one of the two different ways mess with the optimizer? What about if Y is a POD type? Will this force it to call addressof, pass a pointer to the int, and then dereference the pointer?
(I am interested in both a generic C++ answer as well as a C++11 specific one if the two are different.)