I have a list of pointers to objects. What I want to do is read the list and store each object in a dynamic array of that object type. So I do this:
int size = List.size(); // find how many objects in the list
ClassA* object = new ClassA[size]; // create a dynamic array
int counter = 0;
p = List.begin(); // iterator = begining of the list
while( p != List.end() )
{
object[counter] = (*p)->operator=(*(*p));
// called like this as this function is in a separate class
p++;
counter++;
}
This appears to be what I want which means I need the assignment operator but I am a bit confused as to what to put in it and I am getting stack overflow errors, here is what I thought I needed to do:
ClassA ClassA::operator =(const ClassA& source)
{
ClassA* newObject;
newObject = new ClassA;
newObject = source;
return newObject;
}
this is a load of BS I no that but in my head this is what I want it to do but I don't fully understand how I implement it.
If anyone can help or suggest a better way to achieve what I need it would be appreciated.
The reason for doing this is the objects stored on this list are normally iterated through each frame and copied into a temporary object. But the list is not changed during the running of the program, which means I don't need to copy each frame, only once at the start. And I need a dynamic array because I don't know how many objects will be stored in the list.
This could be an operator= implementation:
ClassA &ClassA::operator =(const ClassA& source) {
// check for self-assignment
if(this != &source) {
// copy instance variables.
a = source.a; // for example...
}
// assignment always returns the lvalue
return *this;
}
I don't know your ClassA's instance variables, so you should implement the internal copying.
On the other hand, when iterating your list, you can copy objects this way:
object[counter] = (**p);
(**p) returns, first the pointer stored in the iterator, and then dereferences it.
Related
So, for instance, I have the following code which I want a object's pointer
member to point to a memory which was pointed by another temporary object's
member.
struct A {
int * vals;
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 100;
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
I set temp.vals to nullptr in case the destructor of temp will free that
memory. So far so good, I guess. However, if I change the vals to a dynamic
array, i.e. a pointer to pointers:
struct A {
int ** vals;
A(): vals(new int*[10]) {
for (int i = 0; i < 10; ++i) {
vals[i] = new int;
}
}
~A(){
for (int i = 0; i < 10; ++i) {
delete vals[i]; // illegal to dereference nullptr
}
delete [] vals;
}
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = new int(1);
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
}
I have add a for loop in destructor to handle the nested allocated memory, and
to avoid the memory be freed by the destructor of temp, I set temp.vals to
nullptr, which, however will cause a segmentation fault since when destructor
of temp is called, it is illegal to dereference a nullptr.
So my question is, how to correct set the destructor to handle the dynamic array.
I'm not a native speaker, so please forgive my grammar mistakes.
The typical C++ solution looks a bit different:
class A {
private:
int* vals;
public:
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
A (A const& src); // Copy constructor
A (A&& src) : vals (src.vals) { src.vals = nullptr; }
A& operator=(A const&); // Assignment
A& operator=(A &&);
};
You can now write a = std::move(temp). Outside the class, you don't need to know how the inside works.
For your 2D array, just define the same special member functions. This is usually called the "Rule of Five". If you need a destructor, you probably need the other 4 functions as well. The alternative is the "Rule of Zero". Use std::vector or another class that manages memory for you.
However, if I change the vals to a dynamic array, i.e. a pointer to pointers
In the first program, vals is a pointer. It points to a dynamic array of integers. In the second program, vals is also a pointer. It points to a dynamic array of pointers.
how to correct set the destructor to handle the dynamic array.
You set vals to null. If null is a valid state for vals, then it isn't correct to unconditionally indirect through it in the destructor. You can use a conditional statement to do so only when vals isn't null.
However, the program is hardly safe because vals is public, and thus it is easy to mistakenly write a program where it is assigned to point to memory that isn't owned by the object. In cases where destructor cleans up an owned resource, it is important to encapsulate the resource using private access to prevent accidental violation of class invariants that are necessary to correctly handle the resource.
Now that vals is no longer outside of member functions, you cannot transfer the ownership like you did in your example. The correct way to transfer the ownership is to use move assignment (or constructor). The implicitly generated move constructor cannot handle an owning bare pointer correctly. You must implement them, as well as the copy assignment and constructor.
Furthermore, you should use an owning bare pointer in the first place. You should use a smart pointer instead. If you simply replaced the bare pointers with unique pointer, then the implicitly generated move assignment and constructor would handle the resource correctly, and the copy assignment and constructor would be implicitly deleted.
Lastly, the standard library has a container for dynamic arrays. Its called std::vector. There's typically no need to attempt to re-implement it. So in conclusion, I recommend following:
std::vector<int> a;
{
std::vector<int> temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 1;
}
a = std::move(temp);
}
There are still issues such as the temporary variable being entirely unnecessary, and the loop could be replaced with a standard algorithm, but I tried to keep it close to the original for the sake of comparison.
P.S. It's pretty much never useful to dynamically allocate individual integers.
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.
So I have to write an operator= method in c++ that copies all the values of one array into another. Here's what I wrote:
dynamic_array &dynamic_array::operator=(const dynamic_array &a) {
size = a.get_size();
if (size % BLOCK_SIZE == 0){ //a multiple of BLOCK_SIZE
allocated_size = size;
} else {
int full_blocks = size / BLOCK_SIZE;
allocated_size = (full_blocks+1) * BLOCK_SIZE;
}
try {
array = new int[allocated_size];
} catch (bad_alloc){
throw exception (MEMORY_EXCEPTION);
}
//copy a[i..size-1]
for (int i = 0; i < size; i++){
array[i] = a[i];
}
return *this; //returns a reference to the object
}
So it doesn't assume anything about the sizes and sets the size and allocated size of the array it's given (and using another get_size() method). Now the second code I have to write just says I have to create an array containing a copy of the elements in a. Now I just wrote the same thing as I did for my operator= method (without returning anything):
dynamic_array::dynamic_array(dynamic_array &a) {
size = a.get_size();
if (size % BLOCK_SIZE == 0){ //a multiple of BLOCK_SIZE
allocated_size = size;
} else {
int full_blocks = size / BLOCK_SIZE;
allocated_size = (full_blocks+1) * BLOCK_SIZE;
}
try {
array = new int[allocated_size];
} catch (bad_alloc){
throw exception (MEMORY_EXCEPTION);
}
//copy a[i..size-1]
for (int i = 0; i < size; i++){
array[i] = a[i];
}
}
Now this is giving me the output that I want but I'm just wondering if there's an easier way to do these two methods. The methods are for a dynamic array and I feel like there's more lines of code than needed. The operator= one is supposed to copy the elements of a into a new dynamic array and dynamic_array::dynamic_array(dynamic_array &a) { is supposed to create a new array containing a copy of the elements in a. It sounds like the same code for each method because you always need to create a new array and you will always need to copy the array elements from one array to another but is there a more simpler way to write these two methods or is this the simplest way to do it?
You could simplify both the copy constructor and the copy assignment operator by changing the type of array to std::vector<int>.
The vector does all the work for you and you don't even need any custom implementations at all.
First to make this simpler, you can make use of the fact that you have access to all private members of a. Also the use of memcpy will make this perform better. A couple of lines are added as well to delete the existing array before copying.
dynamic_array &dynamic_array::operator=(const dynamic_array &a) {
size = a.size;
allocated_size = a.allocated_size;
int* newArray = new int[allocated_size];
//copy array
memcpy(newArray, a.array, allocated_size * sizeof(int));
// Delete existing array
if (array != NULL)
delete[] array;
array = newArray;
return *this; //returns a reference to the object
}
Secondly, for copy constructor, a trick we used to do is to call the equal operator inside the copy constructor in order not to repeat the code:
dynamic_array::dynamic_array(dynamic_array &a) : array(NULL) {
*this = a;
}
From Scot Meyers (classic) book "Effective C++":
"In practice, the two copying functions will often have similar bodies, and this may tempt you to try to avoid code duplication by having one function call the other. Your desire to avoid code duplication is laudable, but having one copying function call the other is the wrong way to achieve it.
It makes no sense to have the copy assignment operator call the copy constructor, because you'd be trying to construct an object that already exists. This is so nonsensical, there's not even a syntax for it. There are syntaxes that look like you're doing it, but you're not; and there are syntaxes that do do it in a backwards kind of way, but they corrupt your object under some conditions. So I'm not going to show you any of those syntaxes. Simply accept that having the copy assignment operator call the copy constructor is something you don't want to do.
Trying things the other way around — having the copy constructor call the copy assignment operator — is equally nonsensical. A constructor initializes new objects, but an assignment operator applies only to objects that have already been initialized. Performing an assignment on an object under construction would mean doing something to a not-yet-initialized object that makes sense only for an initialized object. Nonsense! Don't try it.
Instead, if you find that your copy constructor and copy assignment operator have similar code bodies, eliminate the duplication by creating a third member function that both call. Such a function is typically private and is often named init. This strategy is a safe, proven way to eliminate code duplication in copy constructors and copy assignment operators."
And by the way, it'd be wise to also check for self-equality in you assignment operator.
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 have to overload '+' operator for two dynamic containers.
Occurance Occurance::operator +(const Occurance& occ) const {
Occurance* result = new Occurance;
Iterator i1(head);
Iterator i2(occ.head);
while( !(i1.isNULL() && i2.isNULL()) ) {
if(i1.getCount() >= i2.getCount()) {
result->add(i1.getFile());
result->tail->count = i1.getCount();
++i1;
}
else {
result->add(i2.getFile());
result->tail->count = i2.getCount();
++i2;
}
}
return *result;
}
When I do:
Occurance occ = occ1+occ2;
Pointers to the begin of the list are copied correctly and everything works fine but I'm losing reference to result. When occ destructor is called whole list is destroyed, but not the first element of result as I have simply copied it's content instead of reference.
When I change return type to reference the same occurs but during assignment.
Another idea is to not create the 'result' dynamically, so it's automaticly destroyed at the end of function, but then it's calling the destructor which is destroying whole list.
Is there any simple and "proper" way to create such structure and return it without this memory leak? And of course the returned type must be the object or reference as it is expected from '+' operator.
I have figured out a nasty hack involving changing pointer to function in the destructor, but maybe I'm just missing something very simple?
Edit:
Of course class follows the rule of three. Here is assignment:
Occurance& Occurance::operator =(const Occurance& occ) {
destruct();
head = occ.head;
current = occ.current;
tail = occ.tail;
return *this;
}
Occurance::Occurance(const Occurance& occ) {
head = occ.head;
current = occ.current;
tail = occ.tail;
}
Occurance::~Occurance() {
destruct();
}
destruct just destroys the list that starts at 'head'.
The class declaration:
class Occurance {
private:
class Node {
public:
Node* next;
Node* prev;
int count;
const File* file;
Node(const File& a_file, Node* a_prev);
};
Node* head;
Node* tail;
Node* current;
void destruct();
public:
class Iterator {
private:
Node* node;
public:
Iterator();
Iterator(Node* a_node);
void operator ++();
const File& getFile();
int getCount();
bool isNULL();
};
Occurance();
Occurance(const Occurance& occ);
void add(const File& a_file);
Occurance& operator =(const Occurance& occ);
Occurance operator +(const Occurance& occ) const; //dodaje listy zachowując sortowanie
Iterator begin() const;
virtual ~Occurance();
};
Your copy constructor and assignment operator are broken. You either need to do a deep copy of your list, or you need to implement some kind of sharing semantics (e.g. reference counting). You appear to have a linked list, and you are simply copying the head and tail pointers. So when you make a copy, and one is destroyed, it destroys the other one's list too.
I assume your default constructor and/or your add function does some dynamic allocation of nodes. Then your copy constructor and assignment operator need to dynamically allocate nodes too, which are completely independent of the nodes of the object which is being copied. If C++11 is available to you, you should also consider implementing a move constructor, and a move assignment operator.
Once those functions are all correct, your operator+ should look something like this:
Occurance Occurance::operator +(const Occurance& occ) const {
Occurance result; // no dynamic allocation
// operate on result
return result;
}
Another idea is to not create the 'result' dynamically, so it's automaticly destroyed at the end of function, but then it's calling the destructor which is destroying whole list.
You should read about copy constructor. Before the returning object's destructor is called, the copy constructor is called that copies the data from that object to the temporary object that will hold the result of occ1+occ2 operation. I assume you have members that point to dynamically allocated data and in this case, when the copy constructor is called, it assigns the pointer to the temp object instead of allocate new memory and copy data. You must code it on your own. I'd advise you to read: http://www.cplusplus.com/articles/y8hv0pDG/
Also note that you should overload operator = in the same manner if you want to perform this assignment
occ = occ1+occ2
edit: Sorry, I can't comment, could you also copy your class declaration?
In C++, the general principle is to return copies on the stack, not objects allocated on the heap. So in this case you would simply do:
Occurance Occurance::operator +(const Occurance& occ) const
{
Occurance result;
// do whatever
return result;
}
and call it:
Occurance occ = occ1+occ2;
The compiler is smart enough to understand not to make a copy but to re-use the object that you're returning into (this is called return-value optimisation or RVO).
If you really need the object to be the exact same object created inside your function for whatever reason, then you can either: return a smart pointer (look up shared_ptr) or use the new C++11 move operator.