Relatively new to C++, I'm trying to learn using dynamic memory. In this case I'm using it to store member variables.
Quanternion.h -
#ifndef QUATERNION_H_
#define QUATERNION_H_
class Quaternion
{
private:
double* x = new double();
double* y = new double();
double* z = new double();
double* w = new double();
public:
Quaternion(double x, double y, double z, double w);
Quaternion(const Quaternion& q);
Quaternion& operator=(const Quaternion& q);
~Quaternion();
void setQ(double *_x, double *_y, double *_z, double *_w);
double * getX() { return x; }
double * getY() { return y; }
double * getz() { return z; }
double * getw() { return w; }
};
#endif
Quanternion.cpp -
#include "Quaternion.h"
Quaternion::Quaternion(double x, double y, double z, double w)
{
double*a = &x;
double*b = &y;
double*c = &z;
double*d = &w;
setQ(a,b,c,d);
}
Quaternion::Quaternion(const Quaternion & q)
{
this->x = q.x;
this->y = q.y;
this->z = q.z;
this->w = q.w;
}
Quaternion & Quaternion::operator=(const Quaternion & q)
{
if (this == &q)
{
return *this;
}
this->x = q.x;
this->y = q.y;
this->z = q.z;
this->w = q.w;
return *this;
}
Quaternion::~Quaternion()
{
}
void Quaternion::setQ(double *_x, double *_y, double *_z, double *_w)
{
this->x = _x;
this->y = _y;
this->z = _z;
this->w = _w;
}
When I create a Quaternion object and set the fields, and try and print one of the variables such as X by deallocating a pointer. I do not get the result I am expecting.
int main()
{
Quaternion q1(4, 9, 2, 5);
double*d = q1.getX();
cout << d << endl;
cout << *d << endl;
}
Example output -
00B1FB5C
6.26381e+148
Where am I going wrong?
Your code violates basic principles of managing raw pointers - you have no idea who owns them. The same pointer might be an allocated entity through new, or simply an address provided in the constructor. That makes owning those impossible - you can't write assignment operators or copy constructors (your current implmentation is wrong).
The more immediate problem is that you are remembering address of arguments in your 4-doubles constructor. This is the immediate cause for dangling pointer and undefined behavior.
If you want to learn how to use pointers, you need to read a book about it. If you simply need to use pointer-like semantics, use smart pointers.
I am pretty sure you're compiler gave you some warnings. In your constructor, you take the address of of the four initializer arguments x, y, z and w.
This is allowed, but only for using the address inside the constructor function itself. Because when the constructor function is done, these variables are not valid anymore, and therefore, pointers to them point to an invalid memory address (you don't know what's there anymore).
You have two options:
don't use pointers; in this class you don't need them. Copying a pointer takes just as much work as copying a double.
manage your pointers yourself. Create four new doubles in your constructor, and change their value. It might also be nice to look up refreneces.
I understand that you are trying to learn about pointers, but for this applications, pointers are really not necessary. And only make things slower. (Although not much).
you don't have implementation of setQ here
You are trying to pass by value and getting the address of the value in
Quaternion(double x, double y, double z, double w)
When You are trying to pass by value in Quaternion (double x, double y, double z, double w), You get the address of the value. After exit Quaternion (double x, double y, double z, double w) addresses are engaged in these variables are cleared away, and you are using is not your memory.
Related
I use a Vector3 class to represent my actor position, but I need some value to indicate the position value is not set, (0,0,0) is a valid value, because the actor can be there.
One possible can be a larger value, like (9999999,9999999,999999) to indicate this special None value, but's is ugly.
Another possible may be use pointer instead of value.
But I want to hear some suggestions from you.
an option to save actor positions:
vector<tuple<int,int,int>> v;
v.push_back({2,1,4});
v.push_back({1,5,3});
v.push_back({2,1,3});
then use map to indicate positions
typedef tuple <int,int,int> pos;
unordered_map<pos,bool> map;
map[{2,1,4}] = true;
Note that in some older compilers, the function make_tuple has to be used to create a tuple
instead of braces (for example, make_tuple(2,1,4) instead of {2,1,4}).
I definitely don't think that my solutions are the best solutions, but here are two ways:
1.) Don't allow the coordinates to remain uninitialized.
This is relatively simple to implement - just create your own constructor with 3 parameters.
class Vector3{
double x, y, z;
public:
Vector3(double x, double y, double z): x(x), y(y), z(z){}
};
2.) Use exceptions.
A second solution could be that you allow a default constructor with no parameters, but use a hidden attribute called to indicate whether the coordinates have been set or not.
One way of implementing this is the following:
#include <iostream>
#include <stdexcept>
class Vector3{
bool _set;
double x, y, z;
public:
Vector3(){ _set = false; }
Vector3(double x, double y, double z){
x = x; y = y; z = z; _set = true;
}
double get_x(){
if (!_set) throw std::logic_error("Vector3 not initialized!\n");
return x;
}
void set_x(double x){
x = x; _set = true;
}
};
Obviously I've only written the sets and gets for the x coordinate, but you get the point. This way, if somebody attempts to read the coordinates of an uninitialized Vector3, an exception will be thrown. You can then process the exception in a catch block and decide how to act:
int main(){
try{
// this works
auto v1 = Vector3();
v1.set_x(1);
std::cout << v1.get_x() << std::endl;
// this will throw an exception
auto v2 = Vector3();
std::cout << v2.get_x() << std::endl;
}
catch(std::logic_error e){
// decide what to do here
std::cout << e.what();
}
return 0;
}
I have a class Particle:
class Particle {
private:
float x, y, z;
// ...
public:
// ...
float* getPos() {
float p[3] = {x, y, z};
return p;
}
// ...
};
I would call this method like:
Particle a = Particle();
// ...
float* pos = a.getPos();
And then reference the position elements with pos[0] through pos[2].
g++ spouts warning message as stated in the title. But the functionality is exactly how I want it: returning an array. Why does the warning exist and is there a "proper" way to do it?
You can't return a C-array like that, return std::array instead:
std::array<float, 3> getPos() {
std::array<float, 3> p = {x, y, z};
return p;
}
You'll need to include <array> for that.
Personally, I'd skip std::array/std::vector here, because in your particular case, the position of each value imposes independent meaning. In general, sequence types have ordering, tuples have structure; if the element count is fixed (and often heterogeneous) and sorting (or otherwise reordering the values) is intrinsically nonsensical (e.g. in the case of a coordinate, swapping the x and y values changes the meaning), then a tuple makes more sense.
In this case, you could just declare:
std::tuple<float, float, float> getPos() {
// C++17 or higher allows list initialization
return {x, y, z};
// Pre-C++17 you use the std::make_tuple helper
return std::make_tuple(x, y, z);
}
The advantage here is that you can then unpack the result in the caller easily, either with std::tie:
float x, y, z;
std::tie(x, y, z) = a.getPos();
or on C++17 or higher with structured bindings, it's even nicer, since you can declare and initialize the variables with auto, rather than declaring with explicit types, then reassigning with tie:
auto [x, y, z] = a.getPos();
You can store the tuple itself and use std::get if you prefer, but unpacking to useful names rather than obscure std::get indices usually makes for much cleaner code.
You're not returning an array. It's impossible to return an array in C++. You're returning a pointer to an array which no longer exists. Hence the warning.
You could make the array a part of your class and return a pointer to that. In general I wouldn't call that good design
class Particle {
private:
float pos[3];
// ...
public:
// ...
float* getPos() {
return pos;
}
// ...
};
You could return a vector<float> instead. You could return an array<float,3> instead. You could ask yourself why you need this.
p[3] will be destroyed when it goes out of scope so you shouldn't return a pointer to it.
Either return a std::array<float, 3> by value or consider making a class for positions too, and return a Position object, or a reference to it. Example:
struct Position {
float x, y, z;
};
class Particle {
private:
Position m_pos;
// ...
public:
// ...
Position const& getPos() const { return m_pos; }
// ...
};
I'd suggest that you're function is indicative of poor design. Provide getter methods an allow the user of your class to access member variables:
class Particle {
private:
float x, y, z;
public:
float GetX() const { return x; }
float GetY() const { return y; }
float GetZ() const { return z; }
};
Given const Particle a this will let you initialize an array as follows: const float pos[] = { a.GetX(), a.GetY(), a.GetZ() }
Creating a Particle method to allow the user to populate a float[] will encourage the user toward one of the following bad practices:
float* Particle::GetPos() const { return new[3]{ x, y, z }; } creates dynamic memory without clearly informing the caller that the memory needs to be released
array<float, 3U> Particle::GetPos() const { return { x, y, z }; } requires the allocation and creation of a temporary to populate a float[]
void Particle::GetPos(float* param) const { param[0] = x; param[1] = y; param[2] = z; } misses the opportunity for constant arrays and incurs potential caller misuse, as it's not clear that param must have room for at least 3 floats
In my header file, I've defined the Point class, constructs a (x, y) coordinate point, contains a few getter and setter member functions, and contains a toDistance member function, which returns the distance between two points.
class Point
{
private:
double x_coord;
double y_coord;
public:
Point(double x, double y);
Point();
void setXCoord(double);
void setYCoord(double);
double getXCoord();
double getYCoord();
double toDistance(const Point*);
};
Here are the member functions (of interest) in the implementation file:
double Point::getXCoord() {
return x_coord;
}
double Point::getYCoord() {
return y_coord;
}
double Point::toDistance(const Point *P2) {
double p1_x = getXCoord();
double p1_y = getYCoord();
double p2_x = P2.getXCoord();
double p2_y = P2.getYCoord();
double x_distance = p2_x - p1_x;
double y_distance = p2_y - p1_y;
double distance = sqrt(pow(x_distance, 2) + pow(y_distance, 2));
return distance;
}
When running with test data, VS returns the error left of '.getXCoord' must have calls/struct/union' for the lines double p2_x = P2.getXCoord(); and double p2_y = P2.getYCoord();
What am I doing wrong here?
If I understand your question correctly, P2 is const reference. In that case you're not allowed to call non-const functions. You need to make your getter functions const (maybe also the toDistance function). You'd change your functions like this:
double getXCoord() const;
etc. Also make sure to change that in the implementation.
If P2 is a const pointer (not a reference) then in addition you need to modify your calls to be like P2->getXCoord() etc.
I have this class "Point" which takes in x and y as arguments.
However I need to create a constructor that initializes them to random values.
I don't know exactly how it is done. Here's my code:
I created constructors but I'm getting values that are absurd even when I set x and y.
#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;
class Point
{
private:
double x;
double y;
public:
double get_x()
{
return x;
}
void set_x (double x)
{
this->x = x;
}
double get_y()
{
return y;
}
void set_y(double y)
{
this->y = y;
}
double distanceTo(Point p)
{
double x2 = p.get_x();
double y2 = p.get_y();
return sqrt( pow(x-x2,2) + pow(y-y2,2) );
}
Point(double x, double y)
{
x = rand()*1.0 / RAND_MAX * 100;
y = rand()*1.0 / RAND_MAX * 100;
}
Point(){};
};
void main()
{
Point a(1.2,0.5);
Point b;
b.set_x(1);
b.set_y(1);
cout << a.distanceTo(b);
system ("Pause");
}
That's because you aren't initializing your member variables, but changing a copy of the variables that are being passed into the constructor. Hence you're seeing garbage values as x and y (the class versions) are never initialized. You should change this to:
Point()
{
x = rand()*1.0 / RAND_MAX * 100;
y = rand()*1.0 / RAND_MAX * 100;
}
Further, you never call srand() anywhere - you need to do this at some point to properly seed the random generator.
Mistake: You changing local copies of variables passed to constructor by value (they have same name as member variables) and member variables left uninitialized so your program has undefined behavior.
How to fix: You must explicitly indicate what variable you are assigning to. Also, overload you constructor, so you will have one (default) for random values, and one for user-predefined.
Also:
it's better to pass values that not going to be changed in function as constant
you might want pass double by reference, not by value
use initializers lists instead of assignment in constructor body
when using constant references here you don't need to resolve names because you can't change constant values, so compiler will change member variables
Code:
class Point
{
public:
Point() :
x(rand()*1.0 / RAND_MAX * 100),
y(rand()*1.0 / RAND_MAX * 100)
{
}
Point(const double& x, const double& y) :
x(x),
y(x)
{
}
private:
double x, y;
};
int main()
{
Point pt(42, 3.14);
Point pt_random;
}
Same in accessor functions:
double GetX() const { return x; }
void SetX(const double& x) { Point::x = x; }
Because you're altering temporary variables in the constructor (name collision in the same scope). Try:
Point(double x, double y)
{
Point::x = rand()*1.0 / RAND_MAX * 100;
Point::y = rand()*1.0 / RAND_MAX * 100;
}
But that completely disregards arguments given to the constructor. But since now you know how to differentiate between different scopes of variables, you can go on from here, I believe.
Your default constructor does nothing. It doesn't even initialize the values which means they are going to have an unspecified value.
Your constructor taking two arguments just assigns to the arguments, because their names shadow the names of the members.
change
Point(){};
to
Point()
{
x = rand()*1.0 / RAND_MAX * 100;
y = rand()*1.0 / RAND_MAX * 100;
}
also I would advice to change your arguments\members name to avoid mistakes. I personally like to use m_ for members :
private:
double m_x;
double m_y;
You are getting a 'name collision'. In this function
Point(double x, double y)
{
x = rand()*1.0 / RAND_MAX * 100;
y = rand()*1.0 / RAND_MAX * 100;
}
The compiler is doesn't know which x you mean when you assign. The language rules will say that the input arguments should be assigned - but you should not rely on this - because it is needlessly confusing.
A good practice is to adopt a naming convention for member variables. Two common ones are to prefix members with "m" or "_". I like "m" personally.
Then your code becomes:
class Point
{
public:
double mX;
double mY;
Point(double x, double y)
{
mX = rand()*1.0 / RAND_MAX * 100;
mY = rand()*1.0 / RAND_MAX * 100;
}
}
Also the constructor arguments in this case are redundant, and can be removed.
Some of the other answers above are also correct - but it is a sign of bad class design if you have to explicity scope names ( e.g. Point:: ) in simple functions.
First, to get my concern across take a look at these two code segments I have prepared:
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
void Normalise()
{
float num = (((this->X * this->X) + (this->Y * this->Y)) +
(this->Z * this->Z)) + (this->W * this->W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
this->X *= num2;
this->Y *= num2;
this->Z *= num2;
this->W *= num2;
}
void Conjugate()
{
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
};
The above being the 'local methods' within the class that I am referring to in the title..
Now lets take a look at what I mean by the 'static methods' inside the class.
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
static Quaternion& Normalise(Quaternion& quat)
{
float num = (((quat.X * quat.X) + (quat.Y * quat.Y)) +
(quat.Z * quat.Z)) + (quat.W * quat.W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
// Assuming operator= overloaded..
quat = Quaternion(quat.X * num2, quat.Y * num2, quat.Z * num2, quat.W * num2);
return quat;
}
static Quaternion& Conjugate(Quaternion& quat)
{
// Assuming operator= overloaded..
quat = Quaternion(-quat.X, -quat.Y, -quat.Z, quat.W);
return quat;
}
};
My question is.. What is the tradeoff? The effect? To using these static class methods rather than local methods. Both have similar usage:
Edit: Ignore the *.ToString functionality, it is psuedocode - I'm sure you can imagine what it would do; therefore its implementation is redundant as it just prints out raw X, Y, Z, W values.
The 'local method' class usage:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat.Conjugate();
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
Now the 'static method' class usage:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat = Quaternion::Conjugate(testQuat);
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
So what is the difference? These are static methods not objects. Which is preferable? Is it just a matter of design choice?
They are two totally different things. One of them modifies the object in place a la OOP, the other returns a different object a la functional style. If it was my choice, I would keep both of them as there are use cases for both of them. And I would implement the functional styles as free functions based on the member functions, i.e.:
Quaternion normalize( Quaternion quat )
{
quat.normalize();
return quat;
}
[I'm explicitly taking quat by value here, gives a chance for copy-elision]
Note that your static implementations are wrong, they are returning a reference to a temporary. That's undefined behavior, you should get a warning from your compiler and if you are lucky enough a runtime crash as well.
First off, your second approach shouldn't compile although I think MSVC++ has an error allowing temporary objects to be bound to non-const references. Even adding const& doesn't make the functions better: They still don't work because the caller gets hold of a reference to a temporary. So much for the implementation.
With respect to interface design, I think the real trade-off isn't between static members (you can have them additionally, if you want to) but whether the functions taking no parameters should mutate the object themselves or should return a correspondingly modified object:
// return a copy:
Quaternion Quaternion::conjugate() const {
return Quaternion(-this->X, -this->Y, -this->Z, this->W);
}
// modify the object itself:
void Quaternion::conjugate() {
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
Although these two overload actually can live in the same class I would not provide both of them! It is a choice of interface which one is preferable. I would personally prefer the latter and probably create a static member mutating the object itself:
/* static */ void Quaternion::conjugate(Quaternion& object) {
object = object.conjugate();
}
Besides the other answers about differences between the two approaches, the static methods are difficult to mock/stub if you want to employ in unit tests.
For example, suppose that you have a class named ClassThatUsesQuaternion that uses Quaternion. If Quaternion have a lot of static methods you will always have real data. On the other hand, if you transform Quaternion methods into virtual methods, you will be able to redefining all methods, creating a environment test under your control. You can even add a mock framework like gmock to put your expectations.