Consider the following proxy class:
class VertexProxy
{
public:
VertexProxy(double* x, double* y, double* z)
: x_(x), y_(y), z_(z) {}
VertexProxy(const VertexProxy& rhs)
: x_(rhs.x_), y_(rhs.y_), z_(rhs.z_) {}
// Coordinate getters
double x() const {return *x_;}
double y() const {return *y_;}
double z() const {return *z_;}
// Coordinate setters
VertexProxy& x(double val) {*x_ = val; return *this;}
VertexProxy& y(double val) {*y_ = val; return *this;}
VertexProxy& z(double val) {*z_ = val; return *this;}
VertexProxy& operator=(const VertexProxy& rhs)
{
// Should it be this
x_ = rhs.x_; y_ = rhs.y_; z_ = rhs.z_;
// or this?
*x_ = *rhs.x_; *y_ = *rhs.y_; *z_ = *rhs.z_;
return *this;
}
private:
double* x_; double* y_; double* z_;
};
I need to be able to reset the proxy so that it holds different coordinate pointers (similarly to boost::shared_ptr.reset(). In addition, I would like to be able to assign the coordinate values to the ones from a different proxy ( i.e. proxy1.assign(proxy2) ).
What should be the meaning of operator= in my class above? To copy rhs's pointers (shallow copy) or rhs's values? Or should I just make operator= private and provide two members functions to avoid the ambiguity of operator=?
EDIT:
Ok, here's some background information. I'm writing a wrapper around a 3rd party GIS library (shapelib), which stores vertex coordinates (x,y,z,m) in separate arrays (instead of an array of structs). My proxy class is used to make this struct of arrays appear more like an array of structs. It works in tandem with a custom vertex iterator class that makes it much easier to work with ranges of vertices.
Shapelib handles the memory management. All my proxy class does is present a different "view" into the vertex data. When the user manipulates vertex coordinates using my proxy, it actually manipulates the vertex coordinates in the shapelib shape object.
Given that your copy constructor copies the pointers, for consistency your copy-assignment operator should assign the pointers.
VertexProxy& operator=(const VertexProxy& rhs)
{
x_ = rhs.x_;
y_ = rhs.y_;
z_ = rhs.z_;
return *this;
}
It would be very inconsistent if this (admittedly questionable) code:
VertexProxy test( const VertexProxy& other )
{
double tmp1, tmp2, tmp3;
VertexProxy p1( &tmp1, &tmp2, &tmp3 );
p1 = other;
return p1;
}
acted differently to:
VertexProxy test( const VertexProxy& other )
{
double tmp1, tmp2, tmp3; // unused
VertexProxy p1( other );
return p1;
}
It's pretty simple. Do you want VertexProxy to act like a pointer, or a value? If you'd rather it acted like a pointer, then copy the pointers, if you'd rather it acted like a value, copy the values. Nobody can tell you that your class is a pointer or a value (especially since you seem to have something somewhat unusual). If you want better advice, we'd need to know what holds the actual doubles and why.
Quick edit:
Seems to me like actually, if you did the dereference, you'd have it acting like a reference or a pointer. However, the original point remains the same.
std::bitset::reference performs a role similar to my VertexProxy and can be used as a model.
typedef std::bitset<8> Bitset;
Bitset bset1, bset2;
Bitset::reference r1(bset1[3]);
Bitset::reference r2(bset2[3]);
r1 = 1;
r2 = r1;
std::cout << "bset2 = " << bset2 << "\n";
r2 = r1 above copies values.
I would say that it depends on how large the object is.
If the proxy subject is very big then using a reference counting shared pointer is the way to go. Just copy the shared pointer in the copy operation.
If it isn't that big then a deep copy is better. Less hassle all around for everyone.
Related
I have a class like below
class Circle{
private:
int radius;
Circle* next
}
And I gonna creat set/get method...but i have no idea which data type i have to use.
int Circle::getRadius() const{return radius}
or
int& Circle::getRadius() const{return radius}
void Circle::setRadius(int r)
or
void Circle::setRadius(int& r)
CirCle* Circle::getNext() const{return next}
or
Circle& Circle::getNext() const{return *(next)}
void Circle::setNext(Circle& circle)
{
next = new Circle;
next = circle;
}
or
void Circle::setRadius(Circle circle)
{
next = new Circle;
next = circle;
}
or
void Circle::setRadius(Circle* circle)
{
next = circle;
}
I'm famliar with Java quite a lot. And Java argument are all reference. But cpp is quite different so it drive me crazy. Thanks for your help.
First I'd just recommend going through some C++ tutorials. Your question is probably going to get downvoted here because it looks like you really didn't try to search for a solution to your problem, but rather just ask SO for help.
Need to understand a few things with C++. Learn pass by reference vs pass by value. Are primitives passed by reference or by value?
You also should look at pointers. You're kinda mixing up syntax in there a little bit. * is to de reference a pointer. & is to get the memory address of a certain object.
Explore these concepts and you'll find the answer to your question, and learn more about C++.
Try looking at this site for some info.
http://www.learncpp.com/cpp-tutorial/84-access-functions-and-encapsulation/
If you have any other questions, feel free to let me know. :)
Happy to help.
You should use:
int Circle::getRadius() const{return radius}
Why?
First because you don't want your getter to modify your object (that is done by the const after () ), and you don't want caller to your getter to be able to modify your radius either, in fact:
int& Circle::getRadius() const{return radius}
should not even compile. it would have to be:
const int& Circle::getRadius() const{return radius}
In this case the reference to radius returned is const and therefore, the caller cannot modify the radius via this getter.
Although it's totally correct, when dealing with primitive types in C++ one usually prefer to copy rather than to hold const reference. Why? because copy on primitive costs less than have to dereference it each time you need to use it.
Use:
void Circle::setRadius(int r)
Why?
Like before, using an int, prefere to copy the value to use a reference that you'll have to (implicitly) derefence on use.
In this case:
CirCle* Circle::getNext() const{return next}
or
Circle& Circle::getNext() const{return *(next)}
Why? One thing is sure, you won't be able to use the second one, like in the first case your return value will have to be const Circle&. Plus, you want to be able to return a "invalid" value. In C++ not like in Java, you cannot return an "invalid" reference. So the best thing is to return a pointer which will have "NULL" value if "invalid".
After that, if you want your caller to be able to modify the "next Circle" you'll have to go with a Circle* return. If you don't want your caller to be able to modify the result you'll have to go with a const Circle*
const CirCle* Circle::getNext() const{return next}
or
Circle* Circle::getNext() const{return next}
Some people think it's a bad thing to have a const method that return a non const pointer. For certain reasons, I don't, but both are syntaxly correct.
Use:
void Circle::setNext(Circle* circle)
{
next = circle;
}
Why? For your SetNext, it depends on who will have to manage the memory (ie destruction) used by your "next circle" if it's an external class (I think it's the easiest), like a manager for exemple go with that
For your setRadius, simply use:
void Circle::setRadius(int value)
{
radius = value;
}
[Edit: ] Example of Circle class:
Here what would an external manager (like a Circle list) would look like:
class CircleList //Manager as I told
{
public:
Circle* createCircle(int _radius)
{
Circle* circle = new circle(_radius);
//manage here the add to the list of circle
}
void destroyCircle(Circle* _circle)
{
//Manage here the remove of the list
delete _circle;
}
~CircleList()
{
while( first )
{
destroyCircle(first);
}
}
private:
Circle* first = NULL;
};
class Circle
{
public:
Circle(int _radius) : radius(_radius) { }
void setNext(Circle* _circle)
{
next = _circle;
}
Circle* getNext() const
{
return next;
}
void setRadius(int _value)
{
radius = _value;
}
private:
Circle* next = NULL;
int radius = -1;
};
Here, only CircleList manage the list and memory used by circles. If you want to encapsulate even more, make setNext/getNext private and CircleList a friend of circle (once again some will judge, let them :p)
If you wanted to manage memory inside the Circle class, a circle would exist only if its predecessor exist, and if you delete one Circle you would delete all the ones after in the list(I can't see the application this...). In this case you would have something like:
class Circle
{
public:
Circle(int _radius) : radius(_radius) { }
void setNext(int _radius)
{
next = new Circle(radius);
}
void removeNext()
{
delete next;
next = NULL;
}
Circle* getNext() const
{
return next;
}
void setRadius(int _value)
{
radius = _value;
}
~Circle()
{
delete next;
}
private:
Circle* next = NULL;
int radius = -1;
};
Note that you now have a destructor on circle and that when destroying one circle, it destroys all the circle that follow in the list (only way I see to avoid leak and external "holder" of circles)
Plus if you have a really long list, it may cause problems when destroying as a destructor calls (implicitly) the destructor of its successor, you may end up with a stack overflow.
That's why I was telling you that a manager external to the class was the best solution to me, but maybe some other people have better ideas :)
First of all, in Java all are passed by value!
In case of references, it is passed the value of the reference. Because of that it is misunderstood generally.
In case of C++, you can return/pass by value or reference. In your example, int value would be returned by value simply; supposing that probably you would only need its value.
In case of a complex object, you could use reference or pointer. They are actually -almost- the same. You can find sources to look the differences in detail, but here let me tell simply: Pointers are kept in C++ to be compatible with C; references are considered instead. So, you could try to use references mostly.
You need to know the difference of using values by copy and by reference and using pointers.
Passing values by copy, say:
int radius = 2;
setRadius( radius );
Creates a copy of 2 within the function. Whatever changes you do to that value within the function won't change the variable radius that you created outside.
Pointers hold a value that is the memory address of some variable. No matter the type you're using, a pointer only takes up 4 bytes in memory.
int radius = 2;
int *radiusPtr = &radius; // radiusPtr now points to the address of radius
std::cout << *radiusPtr << std::endl; // > 2
setRadius( radiusPtr ); // Passing a pointer to setRadius
Passing by reference is, in a way, similar to pointers but it's defined as "passing the variable itself". You could use a pointer to change the value of the pointed left value, but you can use a reference to change the values of the original variable. You could even use a reference to a pointer to change the original pointer.
int radius = 2;
setRadius( radius ); // Passing by reference is done in the same way as by value, the difference is the method signature -> setRadius( int &radius );
int &radiusRef = radius;
radiusRef = 3;
std::cout << radius << std::endl; // > 3
To answer what to use. Depends on your types and what you need.
//If you use a setter with reference, like
void setRadius( int& radius );
//You cannot pass literal values like
setRadius( 2 );
setRadius( int(2) );
//Only variables/lvalues
int radius = 2;
setRadius( radius );
If you are using a more complex structure then the reference, or a pointer, makes more sense. It's also more efficient to use a reference than it is to copy a huge structure.
The same applies when returning values. If you don't want the user to change the value of your attribute, then a pointer or reference are not the best option. But you could always use a const pointer or reference,
const int *getRadius() const;
const int &getRadius() const;
To prevent the user from changing the radius from outside, yet be able to use the value. The last const means that this function can be called even if you're using a const Circle, or const *Circle or const &Circle.
I'd say for ints you could just use copies, but for more complex structures, like the Circle, consider using references or pointers. In your case, you even store pointers to the next Circle, so a pointer should do.
class Circle{
public:
void SetRadius(int const& value){ radius = value;} // 1
int GetRadius() const {return radius;} // 2
void SetCircle(std::shared_ptr<Circle> const& pCircle) { next = pCircle;} // 3
std::shared_ptr<Circle> GetCircle() { return next; } // 4
private:
int radius;
std::shared_ptr<Circle> next;
}
1 and 3 This is how you write set functions. Period.
2 and 4 Return by value and dont break the encapsulation
3 and 4 NEVER use raw pointers
In my Object Oriented c++ course, we have to write this class that I have put below.
Point
class Point{
public:
Point( double x = 0, double y = 0 );
double getX() const;
double getY() const;
Point & setX( double x ); // mutator, returning reference to self
Point & setY( double y );
const Point & output() const;
double distance( const Point & other ) const;
private:
double xPoint, yPoint;
}; // class Point
my question is...I can't find any information on how the functions setX, setY, and output should work. They are the same type as the class itself and I have written what I would expect them to look like below. Can anyone tell me what I am doing wrong and maybe some more specifics of how these functions are working?
The setX function should change xPoint in the object, the setY should do the same for the yPoint and output should simply output them.
Point & Point::setX( double x )
{
xPoint = x;
}
Point & Point::setY( double y )
{
Ypoint = y;
}
const Point & Point::output() const
{
cout << xPoint << yPoint;
}
Just add a return *this; at the end of your setX and setY: you are returning a reference to your object, so that for example you can do: p0.setX(1.23).setY(3.45), with of course p0 an instance of Point. In the output function, put a separator between xPoint and yPoint, like a space. You say They are the same type as the class itself: don't confuse a variable type with the type returned by a function/method: the method setX, setY and output return a reference to an instance of the class to which they belong. Note that the reference returned by output is const, so you can do:
p0.setX(1.23).setY(3.45).output();
But not:
p0.output().setX(1.23);
As setX is not a const method (it doesn't declare that it won't modify the data inside the class instance to which it belongs).
You can call instead:
double x = p0.output().getX();
because getX is a const method.
Note: I am not saying you should use the methods in this way, but the point is to show what potentially you can do.
Setters are public metods thats allow you change private members of the class, they don't have return type so setX, setY should be void not Point:
void set(double x); // Declaration
void Point::setX( double x ) // Definition outside Point.h
{
xPoint = x;
}
Same with output should be void, rest is fine you can define it whatever you wish to display it, you can change it like this:
void Point::output() const
{
cout << "(" << xPoint << ", " << yPoint << ")";
}
setX() will probably change the value of the pointX member, and return a reference to the object being acted on.
So an implementation might be something like
Point &Point::setX(double xval)
{
if (IsValid(xval)) pointX = xval; // ignore invalid changes
return *this;
}
This can (assuming other member functions and operators are being used correctly) be used in things like this
#include <iostream>
// declaration of Point here
int main()
{
Point p;
std::cout << p.setX(25).setY(30).getX() << '\n';
}
While this example isn't particularly useful (it shows what is possible) the chaining of member function calls is useful in various circumstances. For example, this technique is actually the basis on which iostream insertion and extraction operators work, and allow multiple things to be inserted/extracted to/from a stream in a single statement.
The documentation of the setX and setY functions says
// mutator, returning reference to self
Your implementation does the mutation, but you've failed to complete the contract that this function is supposed to satisfy: it's supposed to return a reference to itself.
this is a pointer to the object you're invoking the method on, and so adding the line
return *this;
would complete the contract.
This is an aside, but it may help you understand why anyone would want to use such a 'strange' design.
You may be familiar with ordinary assignment being used in ways such as
a = b = 0;
if((result = some_function()) == 0) {
// Do something in the `result == 0` case
} else {
// Do something in the `result != 0` case
}
and other similar things. The first example sets both a and b to be 0. The second example stores the return value of the function call into the variable result, and then branches based on whether that value is 0 or not.
The way this works is that x = y is a binary operator that which has the side effect of copying the value of y into x, and then returns that value (technically a reference to x) so that it may be used in the surrounding expression.
So when you write a = b = 0, this is parsed as a = (b = 0), and has the effect of making b zero, and then evaluates to a = 0 which is then evaluated and makes a zero. Similarly for the branching example.
This is something people like to do when writing code (it's a completely separate topic whether or not this is good style), so when people design new types with operator= methods, they design them to support this usage, by making them return a reference to the object assigned to. e.g.
MyClass& MyClass::operator=(arg a)
{
// Copy the value of `a` into this object
return *this;
}
The other assignment operators, like operator+= also work this way.
Now, when you're used to this usage, it is a small step to extend it to other functions that sort of act like assignment, like setX and setY. This has the additional convenience of making it easy to chain modifications, as in point.setX(3).setY(7).
I'm wondering how to get the maximum data locality and performance for the following problem without data copy.
I've a std::vector< MyClass* > where MyClass is something like
class MyClass
{
public:
MyClass(int n,double px,double py,double pz)
{
someField=n;
x=px;
y=py;
z=pz;
anotherField=100;
anotherUnusefulField=-10.0;
}
int someField;
int anotherField;
double x;
double y;
double z;
double anotherUnusefulField;
};
std::vector<MyClass*> myClassVector;
// add some values and set x,y,z
for (std::vector<MyClass*>::iterator iter = myClassVector.begin(); iter!=myClassVector.end();++iter)
{
MyClass *tmp = *iter;
tmp->x+=1.0;
tmp->y+=2.0;
tmp->z+=3.0;
}
I'm iterating frequently on these data and I also would like to enforce data locality. The data contained in the pointer to MyClass should be sent to a OpenGL vertex array, where the vertices are ONLY determined by x,y,z variables. As you may imagine is difficult to correctly set the strides, so I'm here to ask if there are other (portable) solution to this problem.
(p.s. I've already read the post VBOs with std::vector but my case is basically different because I have pointers and I also have other variables inside the class.)
I have pointers
Those pointers are useless to OpenGL, as they're in client address space. Also OpenGL doesn't dereference second level pointers.
and I also have other variables inside the class.
Well, then don't do this. If you passed those class instances to OpenGL you'd copy a lot of useless data. I recommend you just store a index into a tightly packed std::vector or array in your class members, and a reference to the vector/array itself. You can use getter/setter/referencer member functions to abstract away the access to the vector, i.e.
class …
{
// …
std::vector<v_t> *v;
size_t index_v;
x_t getX() const { return (*v)[index_v]; }
x_t setX(x_t x) { return (*v)[index_v] = x;}
x_t &x() { return (*v)[index_v]; }
};
I have a problem. I need to clone objects class containing pointers. An example of the problem is in the following code:
#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <vector>
class CPoint
{
protected:
int m_x;
int m_y;
int *m_p;
public:
CPoint();
CPoint(int x, int y);
~CPoint();
CPoint* clone();
static CPoint* clone(CPoint& p);
int getX();
int getY();
void setX(int x);
void setY(int y);
void toString();
};
int CPoint::getX()
{
return m_x;
}
int CPoint::getY()
{
return m_y;
}
void CPoint::setX( int x )
{
m_x = x;
}
void CPoint::setY( int y )
{
m_y = y;
}
void CPoint::toString()
{
std::cout << "(" << m_x << ", " << m_y<< ", " << *m_p << ")" << std::endl;
}
CPoint::CPoint( int x, int y )
{
m_x = x;
m_y = y;
m_p = new int();
*m_p = x + y;
}
CPoint::CPoint()
{
m_p = new int();
*m_p = 1000;
}
CPoint* CPoint::clone()
{
CPoint *p = new CPoint();
*p = *this;
return p;
}
CPoint* CPoint::clone( CPoint& p )
{
CPoint *q = new CPoint();
*q = p;
return q;
}
CPoint::~CPoint()
{
if (m_p) {
delete m_p;
m_p = NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);
p1->toString();
p2->toString();
CPoint *p3;
p3 = CPoint::clone(*p1);
p3->toString();
CPoint *p4;
p4 = p2->clone();
p4->toString();
p1->setX(50);
p1->setY(60);
p2->setX(80);
p2->setY(90);
p3->toString();
p4->toString();
delete p1;
delete p2;
delete p3;
delete p4;
int a;
std::cin >> a;
return 0;
}
The problem I have with the variable m_p. When clone objects p1 and p2 on p3 and p4, the memory addresses p1 and p3 are different but m_p address is the same. Obviously, when remove p1, p3 removal fails. With p2 and p4 is the same.
How I can clone a CPoint class object?
You seem to be applying the rules of some other Java like language to C++.
This is a fundamental problem and going to lead to all sorts of problems in the long run.
You need to learn the idioms of C++.
In C++ you want to use C++ strings (std::string) not the C-String interface.
#include <string.h> // C-Interface
// What you really want
#include <string> // C++ Interface
If your class contains a pointer then you are probably doing something wrong. RAW pointers should be wrapped in a smart pointer (or containers) to control their lifespan correctly. If you put a pointer into an business class you are breaking the separation of concerns principle.
class CPoint
{
protected:
int m_x;
int m_y;
int *m_p; // What is it supposed to be?
// Who owns it?
Since your class had a pointer it broke the rule of three.
If you wanted to manage the pointer in this class (and you don't (breaking separation of concerns)) then you should have implemented the rule of three (rule of five in C++11) (look it up). If you want to learn how handle a RAW pointer look here https://stackoverflow.com/a/1846409/14065
There is no need for a clone method. This is what the copy constructor is for. You are not writing a class that needs to be cloned (otherwise it would have had a virutal destructor). Your class is not polymorphic and will not be derived from. Thus a copy constructor will work perfectly.
CPoint* clone();
static CPoint* clone(CPoint& p);
// Copy constructor looks like this:
CPoint(CPoint const& rjs)
// Assignment operator looks like this:
CPoint& operator=(CPoint& rhs)
But non of this is required if correctly wrap your RAW pointer in an appropriate class. The compiler generated default versions of these methods will work fine.
Good way to completely destroy encapsulation.
int getX();
int getY();
void setX(int x);
void setY(int y);
To string! Poop. What you really want is a serialization method.
void toString();
// serializer look like this:
friend std::ostream& operator<<(std::ostream& stream, CPoint const& data)
{
// Convert CPoint (data) to the stream.
return stream;
}
In C++ we do not dynamically create objects unless we need to.
And here you do not need to. Creating local objects works better because their lifespan is guaranteed even in the presence of exceptions.
// Rather than dynamically creating them
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);
// Just declare two local variables:
CPoint p1 = CPoint(10, 20);
CPoint p2(30, 40); // Alternative to the above but means the same.
// Much better to use operator<<
// Also shows the functions are badly named. You are not converting to string.
// but rather printing them to a stream.
p1->toString();
p2->toString();
std::cout << p1;
myFileStream << p2; // allows you to easily specify the actual stream.
Copy constructor work much better for copying an object
CPoint *p3;
p3 = CPoint::clone(*p1);
// If we were still using pointers.
CPoint* p3 = new CPoint(p1);
// But much nicer to not even use pointers
CPoint p3(p1);
Its usually a design mistake if you ever see manual call to delete in a function.
delete p1;
delete p2;
delete p3;
delete p4;
If you have pointers wrapping them in smart pointers (or container) like classes makes them exception safe to use. This is because for local objects the destructor is guaranteed to be called and thus your object will correctly deleted the pointer when it goes out of scope. Currently this code is not exception safe and will leak if an exception propagates passed them.
Small note: main() is special. If you don't specify a return value the compiler plants return 0; for you. If your application has no error state best to use this functionality as a sign to other developer that your code will always exit cleanly.
return 0;
I would re-write like this:
#include <iostream>
#include <string>
#include <vector>
class CPoint
{
protected:
int m_x;
int m_y;
std::vector<int> m_p;
public:
// If you don't explicitly initialize m_x and m_y them
// they will have indeterminate (random) values.
CPoint() : m_x(0), m_y(0) {m_p.push_back(1000);}
CPoint(int x, int y) : m_x(x), m_y(y) {m_p.push_back(x + y);}
int getX() { return m_x;}
int getY() { return m_y;}
void setX(int x) { m_x = x;}
void setY(int y) { m_y = y;}
friend std::ostream& operator<<(std::ostream& stream, CPoint const& d)
{
return stream << "(" << d.m_x << ", " << d.m_y<< ", " << d.m_p[0] << ")" << std::endl;
}
};
int main(int argc, char* argv[])
{
CPoint p1(10, 20);
CPoint p2(30, 40);
std::cout << p1 << p2;
CPoint p3(p1);
std::cout << p3;
CPoint p4(p2);
std::cout << p4;
p1.setX(50);
p1.setY(60);
p2.setX(80);
p2.setY(90);
std::cout << p1 << p2 << p3 << p4;
int a;
std::cin >> a;
}
In this example is an integer but may be any type. The question I had was like to clone an object that contains a pointer to another type.
I believe that there are basically two situations here: you want the containing object to own the pointed-to object; or you don't want the containing object to own the pointed-to object.
Let's start with non-owning. What's the tool that C++ provides to represent non-owning pointers? Well, regular pointers are non-owning. And how do you copy a regular pointer? You do nothing. You let the compiler deal with it, generating the correct copy constructor that you can use at will (and while you're at it, let the compiler generate a destructor as well).
And what about owning? What's the tool for owning pointers? Well, for most cases you don't even need a pointer for that: just store a value directly and, again, let the compiler generate the correct copy constructor (and a destructor too!). In the example provided int m_p; would work nicely.
There is an annoyance in this situation when polymorphic base classes are involved: copying may cause slicing. Does C++ provide a tool for this situation? Sadly, it doesn't. You have to write it by hand. But do yourself a favour and don't mix these concerns with the rest of the class (Single Responsibility Principle).
Write a reusable class (bonus points: make it a template) that owns a single pointer, cleans it up on destruction, and performs a polymorphic copy (a common idiom involves a virtual clone function) in the copy constructor. Then put a value of that reusable class in your CPoint and... you guessed it! Let the compiler generate the correct copy constructor.
In addition to shallow-copying the immediate data members m_x and m_y, you need to deep-copy the pointer member m_p. Since you haven't shown the constructor for this class or what m_p really points to, I'm going to assume that m_p points to the first element of an array of int. Deep-copying this entails:
Instantiate a new array of int that is the same (or larger) size as the original array
Copy each element from the original array to the new array
Set m_p in the cloned object to point to the first element of this new array
An example of how this might be done:
CPoint* CPoint::clone(CPoint& rhs)
{
CPoint* ret = new CPoint;
ret->m_x = rhs.m_x;
ret->m_y = rhs.m_y;
size_t m_p_count = /* somehow determine the size of rhs.m_p */;
ret->m_p = new int[m_p_count];
std::copy(&rhs.m_p[0], &rhs.m_p[m_p_count], ret->m_p);
return ret;
}
A few notes about your code:
You would be better off using a vector<int> instead of a raw pointer to an array of int.
Barring #1, you should be using smart pointers instead of raw pointers
I don't see any way in the code above to determine the size of the array. This would be easy if you used a vector<int> -- just call vecctor<int>::size(). You need to know the size of the array in order to make a copy of it, obviously.
A clone() type function is generally only useful when making a copy of a polymorphic object via a base class pointer. Since your class, and your useage of it, does not fall in to this category, a clone() function is not the right way to go in the first place. Consider using a copy constructor and a copy assignment operator instead, and don't forget to also implement a destructor. Better still, avoid all of this stuff altogether and follow the Rule of Zero.
You must reallocate memory for all pointers within CPoint and copy their data into new memory. In your case you have to do following operation:
CPoint clone()
{
CPoint p;
p = *this;
p.m_p = new int();
*p.m_p = *m_p;
return p;
}
You have to ask yourself: Does each instance of your object "own" the object it points to, or do they all refer to a common object owned by something else?
When you have a case of ownership, each instance must point to an individual copy. That means that you don't have to copy the pointer, you have to create a clone of the object it points to and assign this new object to the pointer of the copy.
Assuming that m_p points to only one integer (and not a whole array), cloning can be done like this:
CPoint* CPoint::clone()
{
CPoint* cloned = new CPoint(m_x, m_y);
if (m_p)
{
cloned->m_p = new int;
*cloned->m_p = *m_p;
}
return cloned;
}
Note that such a member pointer has the sole purpose of adding the additional possibility of having a NULL-value - which can have a separate meaning.
Note also that the following has to be done to avoid memory leaks and heap corruption:
The copy constructor and assignment operator have to be "disabled" (declared private)
The destructor must delete m_p.
I'm trying to construct a class for colors in C++,
this is not an homework is just that I'm still struggling with references and const.
--Color.h
class Color{
private:
double r;
double g;
double b;
double a;
public:
//constructor, getters and setters...
Color& operator =(Color& other_color); //(1)
}
--Color.cpp
Color& operator=(Color& other_color){
this->r = other_color.get_r(); //line 41
this->b = other_color.get_b();
//and so on...
return *this;
}
like this it works fine but I heard one has to put a const to avoid that by fault the object will be modified by the assignement operation, so one has to declare the other object as const. Like this:
Color& operator =(Color const& other_color); //(2)
but it gives me this errors:
/Users/../color.cpp:41: error: passing 'const Color' as 'this' argument of 'float Color::get_r()' discards qualifiers
so here is my question...
what is happening here? second what would happen if I don't declare other_color as const? what are the possible errors?
PS.: little bonus question:
I want to pass my variable to the opengl glColor4v(colorx.return_rgba()) returning the array [r,g,b,a] of the class Color. This:
float* Color::return_rgba(){
float rgba[4] = {this->r, this->g, this->b, this->a};
return rgba;
}
won't work because rgba won't be in scope anymore after the return so it will be deleted and my pointer will point to not initialized adresses, damn...
passing 'const Color' as 'this' argument of 'float Color::get_r()' discards qualifiers
This means you have to take it further. get_r is probably declared as
float get_r()
and to make it work (const-correctly), you should make it
float get_r() const
second what would happen if I don't declare other_color as const?
You would be unable to assign from const-qualified Colors. You usually want to be able to use const objects, among other as source of assignment. Moreover, it makes the intent not to modify the source clear to the reader of the code.
I want to pass my variable to the opengl glColor4v(colorx.return_rgba()) returning the array [r,g,b,a] of the class Color.
Return a special "vehicle" that would contain the array and convert automatically to float*. Something along
struct ColorQuadruplet
{
float data_[4];
// add initialization and such here
operator float*() { return data_; }
};
ColorQuadruplet Color::get_rgba() const
{
ColorQuadruplet ret;
// fill ret
return ret;
}
You have two choices here. One is for your operator= to directly access to the members of the source object:
Color &operator=(Color const &other) {
r = other.r;
g = other.g;
b = other.b;
a = other.a;
}
The other (which you probably want to do in any case, if you insist on having accessors for the color components at all) is to const-qualify the accessors you've written:
double get_r() const { return r; }
^^^^^
The const here is the part I've added that you apparently don't have.
Edit: as far as passing the values to glColor goes, I'd consider a small front-end something like this:
gl_color(Color const &c) {
glColor4d(c.r, c.g, c.b, c.a);
}