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.
Related
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;
}
I have seen several examples of copy assignment operator and could not understand why do we need to delete pointers inside copy assignment operator. For example if I have the following class
class MyClass
{
public:
MyClass(int a)
{
x = new int(a);
}
MyClass& operator=(const MyClass& pMyClass)
{
*x = *(pMyClass.x);
// ?????????
// delete x;
// x = new int(*(pMyClass.x));
}
~MyClass()
{
delete x;
}
private:
int* x;
}
What is wrong with *x = *(pMyClass.x) line? I am just copying object pointed by pMyClass.x why I need to delete and create it again?. Could anyone please give example when this code will cause memory leak?
So this is an example [extracted from Bjarne Stroustrup's "A tour of C++ (2nd edition)] of a copy assignment of a user defined vector class:
Vector& Vector::operator=(const Vector& a) // copy assignment
{
double∗ p = new double[a.sz];
for (int i=0; i!=a.sz; ++i)
p[i] = a.elem[i];
delete[] elem; // delete old elements
elem = p; // here elem is the vector's data holding member array
sz = a.sz;
return ∗this;
}
To understand why at line 6 we have the deletion operation:
delete[] elem; // delete old elements
we first need to first understand the distinction between copy constructor and copy assignment. In the first case (copy constructor) we create a completely new object, whereas in the second case (copy assignment, the one we're actually interested in) we already have an existing object into which we just want to copy the contents of another given object of the same type.
Given the fact that we already have an existing object, we first need to clear it's contents so that we are then able to copy the desired content from the object we intent to copy.
I hope that answers your question.
It is a valid code. But if instead of the pointer to a single object you will have a pointer to first element of an array and arrays may have different sizes then you need to delete the array that to reallocate it with the new size.
Nothing wrong with *x = *(pMyClass.x) when you copying value from one class instance to other. I think, in general, deleting an object (if it is not just int) can prevent usage of new object with new data if before operator= execution address stored in x was sent to some other part of program.
I'm currently trying to work out a .cpp file for a project, but I'm getting a seg fault whenever I try to run it with the test file provided to met. I suspect I've found where the error occurs, but I can't for the life of me find a solution.
Basically, the class Product is initialized in the test file as seen below
Product * orderItem = new Product(*wonkaBar_retail);
Where wonkaBar_retail is a pointer to a Product object - so basically, the constructor for Product takes in an object of its own type... I'm not even sure that's supposed to work. As I said, this code, including the part that instantiates wonkaBar_retail was provided, so I tried compensating by making a Constructor like this
Product(Product) {
//Constructor in the header file
}
and even like this
Product(const Product&) {
//Other style
}
That just gave me a handful of compiler errors the compiler didn't even bother to explain...
Can someone clarify how this is supposed to work, and if this would even cause a segfault in the first place?
The line you provided uses a copy constructor for the class Product which is perfectly legal. In fact, if you don't provide your own copy constructor for a class a compiler will generate one for you.
A copy constructor takes a reference to another object of the same type and initializes a new object to the same state as the other object. The copy constructor signature usually looks like this:
Product(const Product& other);
For simple classes the compiler generated copy constructor will work just fine, however for non-trivial classes, e.g. containing pointers to dynamically allocated objects you should implement your own.
Consider the following class:
class Buffer
{
public:
Buffer(int dataSize) : m_dataSize(dataSize) { m_data = new char[m_dataSize]; }
~Buffer() { delete[] m_data; }
private:
int m_dataSize;
char* m_data;
};
The default copy constructor for this class will look like this:
Buffer::Buffer(const Buffer& other)
{
m_dataSize = other.m_dataSize;
m_data = other.m_data;
}
This is clearly not what you want. For one, if an object you copy gets deleted, the data your new object is pointing to will also get deleted. And then when you delete your new object you'll attempt to delete the same data twice, which is very bad.
What you really want to do then is to allocate new m_data for your new object and copy the data from the other object like this:
Buffer::Buffer(const Buffer& other)
{
m_dataSize = other.m_dataSize;
m_data = new char[m_dataSize];
for (int i = 0; i < m_dataSize; ++i)
{
m_data[i] = other.m_data[i];
}
}
I create a class type Test and constructor with parameter, however, when I want to assign the constructor I create to a new constructor through the function f, the program crashes! Did anybody know why!?
The code:
class Test
{
public:
int number;
int *a;
Test(int n){
a = new int[n];
}
~Test(){
delete []a;
}
};
Test f(Test Ft1)
{
// Do something.
return Ft1;
}
int main()
{
Test t1(3);
t1.number = 5;
Test t2 = f(t1);
return 0;
}
The problem is that you are deleting twice the same array a when t1 and t2 destructors are called:
t1 and t2 have their member variable a pointing to the same memory location. When you do Test t2 = f(t1), a copy of t1 is created and is assigned to t2. You did not define a specific copy constructor, so the compiler defined it implicitly for you. However it simply copies the value of a (and does not do a new allocation as you might expect).
As best practice, I would recommend to add your own:
- copy constructor
- copy assignment
(cf rule of three)
Concerning the variable member a design:
- If you want t1 and t2 to point to the same array, then you can use shared_ptr
- If you want t1 and t2 to have their own array, then it would be simpler to use a vector<int> for a
Edit: in case you need to use a raw pointer, here is a quick example of how you can manage the memory in copy constructor and operator assignment. May I recommend you to read a reference book about it (for instance Effective C++ , chapter 11)? It will explain you the key concepts and the pitfalls.
class Test{
public:
int number;
int *a;
Test(int n){
a = new int[n];
}
~Test(){
delete [] a;
}
Test(const Test& that)
{
int size = sizeof(that.a);
a = new int[size];
memcpy (a, that.a, sizeof(size));
}
Test& operator=(const Test& that)
{
if (this != &that)
{
delete [] a;
int size = sizeof(that.a);
a = new int[size];
memcpy (a, that.a, sizeof(size));
}
return *this;
}
};
Test f(Test Ft1){
//do something
return Ft1;
}
int main(){
Test t1(3);
t1.number = 5;
Test t2 = f(t1);
// Test t3(t1); // calls copy constructor
// t3 = t1; // calls assignment operator
return 0;
}
The cause of your problem is that there is a thing called "binary copy". When special assignment/copy constructors are not defined, this binary copy kicks in. When one of your object gets copied over another, 2 different instances start own the same array because the pointer gets overwritten and the original array from the destination object gets leaked.
Compiler thinks that it is ok to copy contents of one object to another with a simple memcpy() (the picture is slightly more simplified but in essence what I write is correct). This is a constant source of problems, but this is how the language is defined. There is no way to do it any other way today. Tons of code are written and these tons expect exactly this.
First you need to decide what should happen with this array after copying. Should both objects co-own the array of the source object, should this array be duplicated at this point or anything else. Once you decide this, you need to implement this strategy in the assignment/copy constructors.
#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.