Copying pointers to another list elements in assign operator - c++

I have some problem with coming up with idea how to design objects copying in my application due to the pointers issue in one of the objects. Simplest schema looks like this:
MyMapClass.h
class MyMapClass
{
public:
std::vector<Point> points;
std::vector<Road> roads;
MyMapClass& operator=(const MyMapClass&);
}
MyMapClass.cpp
MyMapClass& MyMapClass::operator=(const MyMapClass& m)
{
points = m.points;
roads = m.roads; // here is error
return *this;
}
Point.h
class Point
{
public:
std::string name;
std::vector<float> position;
}
Road.h
class Road
{
public:
Point* source;
Point* destination;
}
Originally it was designed without need to copy MyMapClass object and it took me a while to spot that error.
As I understand now, when I am copying both vectors to new objects addresses in elements of roads to source and destination stays this same. So when the old object is destroyed the pointers in roads elements just point to garbage.
How would you recommend copying also roads vector so that it's elements will point to new objects?

If you can, use objects of type Point instead of Point* in Road.
class Road
{
public:
Point source;
Point destination;
};
If you must use pointers, follow The Rule of Three.
Also, if you must use pointers, consider using smart pointers, std::shared_ptr or std::unique_ptr, instead of raw pointers.

Just create a copy constructor for class Road ... The copy assignment of std::vector will invoke the copy constructor of each element....
class Road
{
public:
Point* source;
Point* destination;
Road(const Road& r) { /* implement copy operations of source and destination here */ }
}
Then the assignment here will invoke the above copy constructor in creating all the new elements
MyMapClass& MyMapClass::operator=(const MyMapClass& m)
{
points = m.points;
roads = m.roads; // invokes copy constructor m.roads.size() times
return *this;
}

Related

How to delete a pointer belonging to an object stored in a vector?

I have a Containing class, a Contained class, and a Data class. That Containing class holds a vector of Contained objects. The Contained class holds a pointer to a data object, allocated on the heap in Contained's constructor. However, I can't deallocate it in the destructor, since the vector will create copies of Contained and then destroy them, thus destroying the data pointer even in the copy we're using.
TL;DR Here's some code to explain:
class Data {
public:
Data();
};
class Contained {
private:
Data* data;
public:
Contained();
// what should I add ? a copy constructor ? an assignement operator ? and how
};
class Container {
private:
vector<Contained> rooms;
public:
//some member functions
};
Contained::Contained() {
data = new Data();
}
Where do I delete data ?
Using RAII(Resource Acquisition is Initialization)
Add a destructor to the Contained class:
Contained::~Contained() {
delete data;
}
This will ensure whenever your contained object goes out of scope, it will automatically delete the data pointer it has. So if you do
//delete first element
rooms.erase(rooms.begin());
data ptr of that object will automatically be deleted.
Using smart pointers
Use std::unique_ptr<T>.
class Contained {
private:
std::unique_ptr<Data> data;
public:
Contained();
// what should I add ? a copy constructor ? an assignement operator ? and how
};
and in the constructor:
Contained::Contained() {
data = std::make_unique<Data>();
}
Using smart pointers i.e., (unique_ptr, shared_ptr) ensures your pointer will automatically delete when no one is owning it. Since you can not copy unique_ptr but only move it, you should define a move constructor and move assignment operator on the Contained class.
Contained::Contained(Contained&& other)
: data(std::move(other.data))
{}
Contained& operator=(Contained&& rhs) {
if (this != &other) {
data = std::move(rhs.data);
}
return *this;
}

Deleting an Object in c++ implies deletion of its members?

I am quite new to c++ and I have a question.
If I have a class containing a (pointer to a) vector:
class myClass {
public:
int* direction;
myClass(int d){direction=new int[d];}
}
When I create an object and delete it in the main:
int main(){
int d;
myClass* myvec;
myvec = new myClass(d);
delete myvec;
}
Also the destructor for myvec->direction has been coherently called and the memory freed? Or do I have to write an apposite method for that?
I hope the question is clear...
If you've allocated memory with new you need to delete it too, like this:
class myClass {
int* direction;
public:
myClass(int d) : direction(new int[d]) {}
~myClass() {
delete[] direction;
}
}
But you'd also need to write a copy constructor and copy assignment operator, and in C++11 and later also a move constructor and move assignment operator, for this to be working good. Otherwise, you'd risk the default versions of those copying the raw pointer when you use instances of this class.
Take a look at the rule of three/five/zero.
You'd be much better off using a std::vector<int> instead of a raw pointer.

C++ Object Vector

I am relatively new to creating object vectors. The below is the code that my object used prior to me including a holding vector:
class obj {
public:
int* arr;
obj(int x) {
arr = new int[x];
}
~obj() {
delete[] arr;
}
// All functionality stripped for clarity
};
I would now like to create a vector to hold all of the created objs. What I have tried is to create a vector and just push the newly created objects into it akin to the below:
std::vector<obj> objVector;
objVector.push_back(obj(5));
objVector.push_back(obj(8));
The above leads to errors where arr has not been created and is an empty pointer. The suggestion I have seen elsewhere on this site is to include a copy creator to facilitate. So I have the below questions:
Using the above push_back code will there be 2 objects created (A temporary one and the vector one) or will one be created directly into the vector.
What do I have to include in the copy creator, Will I have to create a new arr for the second object or could I just pass it onto the second.
Also if this is a poor way to implement a holder of objects then please could you point me towards a source where I could read up on this.
Hello All, I have had to edit this as it has been marked as a duplicate. Please note I am aware of the rule of three / five and have alluded to know that I need to include this above. My actually questions in the bullet points are around how the vector handles and object being pushed.
Does this create a temporary object and runs it constructor then performs a copy of this temporary object into the vector. Or conversely does it create the object straight into the vector.
Also as commented below it would seem that emplacing the object into the vector will avoid the need for a copy function as it seems to create the object directly. I am aware I will still need to implement the rule I am just trying to understand what the standardised code is doing and how it works.
You need a copy/move constructor and to retain the size of the array. See the famous Rule of 3/5
class obj {
public:
int* arr;
const size_t size;
obj(const obj& other)
:size(other.size)
{
arr = new int[size];
std::copy(other.arr,other.arr+size,arr);
}
obj& operator=(const obj&) = delete; // unclear what to do if size!=other.size
obj& operator=(obj&&) = delete; // unclear what to do if size!=other.size
obj(obj&& other)
:size(other.size)
{
arr = other.arr;
other.arr=nullptr;
}
obj(size_t x)
:size(x)
{
assert(x>0);
arr = new int[x];
}
~obj() {
if(arr)
delete[] arr;
}
// All functionality stripped for clarity
};
P.S.
No need to be so dogmatic on smart pointers. They help but we survived 30 years without them.

Why doesn't the copy constructor get called?

I have this code for copying a polygon class. The problem I have is that in the end the vertices point to the original polygon class location. Since the copy constructor does not seem to be invoked. Why is that ?
Polygon::Polygon(const Polygon &aPolyToCopy)
{
int i;
vertices = new Vertex[aPolyToCopy.count];
for (i=0;i<aPolyToCopy.count;i++)
{
vertices[i].x = aPolyToCopy.vertices[i].x;
vertices[i].y = aPolyToCopy.vertices[i].y;
}
count = aPolyToCopy.count;
}
In a list template I do this
template <class T, int i>
bool SortedVector<T, i>::add ( const T& v )
{
myClass[myCurrent] = v; //Copy constructor not called ?
myCurrent++;
return true;
}
The template is
template <class T, int i>
class SortedVector
{
public:
int maxSize;
T myClass[i];
int myCurrent;
SortedVector();
~SortedVector();
bool add ( const T& v );
};
You're doing an assignment, you don't construct a new object here. If you define a custom copy constructor, you also need to overload operator=
See http://www.learncpp.com/cpp-tutorial/911-the-copy-constructor-and-overloading-the-assignment-operator/ for example.
If you would do something like x = Polygon(y), then your copy constructor would be called (followed by the default operator=). But don't use this workaround, just provide your operator=.
I think a problem in your Polygon class is that you have a vertices data member, which seems to be a raw pointer to a Vertex, used to store a raw array allocated with new[]:
vertices = new Vertex[aPolyToCopy.count];
You may need to overload also operator= (and the destructor), not only the copy constructor (see The Rule of Three); you haven't showed all the code of your Polygon class, so it's not clear if you defined proper copy assignment and destruction.
Note that you will simplify your code if you use a robust RAII container class like std::vector.
Just add a "std::vector<Vertex> vertices;" data member instead of a "Vertex* vertices" data member, and std::vector will take care of copy, cleanup, etc. You don't need to do anything: it's all automatically managed by std::vector.
#include <vector> // for std::vector
class Polygon
{
std::vector<Vertex> vertices;
public:
explicit Polygon(size_t vertexCount)
: vertices(vertexCount) // Build a polygon with specified vertices
{}
//
// Compiler generated copy constructor, operator= and destructor are fine.
//
};
In general, in C++ try to build classes assembling together convenient RAII building blocks like std::vector and other direct resource managers.

Deallocating memory from a private class variable

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class myClass{
public:
int *num1;
myClass();
};
myClass::myClass(){
num1 = new int[1];
num1[0] = 10;
}
int main()
{
myClass *myclass;
myclass = new myClass[10];
cout << myclass[0].num1[0] << endl;
delete &myclass[0];
cout << myclass[0].num1[0] << endl;
}
I want to delete the first instance of myclass (myclass[0]).
This code does not run correctly, it fails during the delete part. There is probably something I am missing.
What did I do wrong?
You cannot delete just a portion of an array created with new. new allocates a block of memory which can only be deleteed all together.
If you want an object to free its own internal data you'll have to arrange for the class, which should encapsulate and hide its own internal resources, to do that itself.
If you want a smaller block of memory holding the array you allocated, then you must allocate a smaller block and move the contents that you wish to keep into the new block, and then delete the entire old block:
int *arr = new int[10];
int *tmp = new int[9];
std::copy(arr+1, arr+10, tmp);
delete [] arr;
arr = tmp;
You need to design your class to manage its own resources, and to handle copying or moving. Your current myClass allocates an array but relies on other code to handle cleaning up. This is not a good way to go about doing this, because often no other code is in a good position to do the correct thing, and even when you could you'll very frequently make mistakes.
Since you're allocating in the constructor you need a destructor that handles deallocation. And then since you implement one of three special operations (copy-ctor, copy-assignment, destructor) you need to consider implementing them all. (This is called 'The Rule of Three'. In C++11 it becomes 'The Rule of Five' with the addition of move-ctors and move assignment.)
class myClass {
public:
myClass();
// destructor to handle destroying internal resources correctly
~myClass();
// copy constructor and copy assignment operator, to handle copying correctly
myClass(myClass const &rhs);
myClass &operator=(myClass const &rhs);
// move constructor and move assignment operator, to handle moves correctly (C++11)
myClass(myClass && rhs);
myClass &operator= (myClass &&rhs);
private:
int *num1; // private so external code can't screw it up
public:
// limited access to num1
int size() const { if (num1) return 1; else return 0; }
int &operator[] (size_t i) { return num1[i]; }
};
You can implement the constructor just as you did, or you could use the initializer list and C++11 uniform initialization:
myClass::myClass() : num1(new int[1]{10}) {}
Now, the destructor you want depends on the semantics you want the class to have, and the particular invariants you want to maintain. 'value' semantics are the norm in C++ (if you're familiar with Java or C# those languages encourage or require 'reference' semantics for user defined types). Here's a destructor you might use if you want value semantics, and if you maintain an invariant that num1 always owns memory or is null.
myClass::~myClass() { delete num1; }
Copying and moving can be handled in different ways. If you want to disallow them entirely you can say (in C++11):
myClass::myClass(myClass const &rhs) = delete;
myClass &myClass::operator=(myClass const &rhs) = delete;
myClass::myClass(myClass && rhs) = delete;
myClass &myClass::operator= (myClass &&rhs) = delete;
Or if you want to allow copying and or moving (and maintain value semantics and the invariant mentioned above) then you can implement either or both of these pairs of functions:
myClass::myClass(myClass const &rhs) : num1( rhs.size() ? new int[1]{rhs[0]} : nullptr) {}
myClass &myClass::operator=(myClass const &rhs) {
if (num1)
num1[0] = rhs[0];
}
myClass::myClass(myClass && rhs) : num1(rhs.num1) { rhs.num1 = nullptr; } // remember to maintain the invariant that num1 owns the thing it points at, and since raw pointers don't handle shared ownership only one thing can own the int, and therefore only one myClass may point at it. rhs.num1 must be made to point at something else...
myClass &myClass::operator= (myClass &&rhs) { std::swap(num1, rhs.num1); } // steal rhs.num1 and leave it to rhs to destroy our own num1 if necessary. We could also destroy it ourselves if we wanted to.
With this implementation you can now treat a myClass object the same as you would an int or any other 'value' type. You no longer need to worry about managing its internal resources; it will take care of them itself.
int main() {
std::vector<myClass> myclassvec(10);
cout << myclassvec[0][0] << '\n';
myclassvec.erase(myclassvec.begin()); // erase the first element
cout << myclassvec[0][0] << '\n'; // access the new first element (previously the second element);
}
Create a function inside of your class the handles the deletion of its private members, maybe called FreeMem(int index)
void myClass::FreeMem()
{
delete [] num1
}
But honestly, freeing memory of an object without the use of a destructor in this sort of a program is hazardous and downright bad practice. I would recommend freeing the memory in your destructor, so when the object terminates it frees the memory,
myClass::~myClass()
{
delete [] num1;
}
Another thing to note on, if you're only creating one value in your dynamic variable, it would be easier to write it as:
int * pnum = new int;
//or in your class..
pnum = new int;
among other things, you have a lot of flaws in your program. I would recommend re-reading up on classes again.