could you tell me why does this code crash? - c++

So I'm curious of the reason the following code crashes.
Will appreciate help.
#include <iostream>
using namespace std;
class temp
{
public:
temp(int i)
{
intPtr = new int(i);
}
~temp()
{
delete intPtr;
}
private:
int* intPtr;
};
void f (temp fInput)
{
cout << "f called" << endl;
}
int main()
{
temp x = 2;
f(x);
return 0;
}

You are violating The Rule of Three
You maintain a pointer member and you pass a copy of the object to the function f. So, the end result is that you call delete twice on the same pointer.

The crash occurs because of the way you are passing x.
After the scope of the f function, x's destructure will be called and will delete intPtr.
However, that will delete memory that is still in scope for main. Therefor, after return 0 is called, it will try to delete memory that already exists as you are calling delete twice on the same pointer.
To fix this error, change
void f (temp fInput)
to
void f (const temp& fInput)
Alternatively, you could look into using a std::shared_ptr.

The pointer is copied when x is passed (implicit copy constructor) and the destructor is called twice (before the function returns and before main returns), thus the memory is deleted twice.
Use std::shared_ptr<int> here instead instead of a raw int pointer (assuming you want the behavior to be the same, i.e. reference the same int from both temps; otherwise, implement the copy constructor, move constructor and assignment operator yourself).
#include <memory>
class temp {
public:
temp(int i) : intPtr(std::make_shared<int>(i)) {
}
private:
std::shared_ptr<int> intPtr; // reference counting ftw
};

The problem you're hitting here is a double delete. Because you didn't define any copy constructors here C++ is happily doing so for you. The implementation does this by performing a shallow copy of all of the contents.
f(x);
This line works by creating a copy of x and passing it to f. At this point there are 2 temp instances which own a single intPtr member. Both instances will delete that pointer and this is likely what is causing your crash.
To work around this you can take a number of steps
Use a pointer type meant for sharing like shared_ptr<T>
Create an uncallable copy constructor which forces the instance to be passed by ref
An example of #2 is
class temp {
temp(const temp& other);
temp& operator=(const temp& other);
public:
// Same
};
Now the f(x) line simply won't compile because it can't access the necessary copy constructor. It forces it to instead redefine f to prevent a copy.
void f(const temp& fInput) {
...
}

Related

How to avoid deletion of object given as a parameter in C++

I am new to C++ and I do not know how to solve the following problem.
The class Foo has a constructor which creates a array of doubles of a given size. The destructor deletes this array. The print method prints the array.
#include <iostream>
class Foo {
private:
int size;
double* d;
public:
Foo(int size);
~Foo();
void print();
};
Foo::Foo(int size)
{
this->size = size;
d = new double[size];
for (int i = 0; i < size; i++)
{
d[i] = size * i;
}
}
Foo::~Foo()
{
delete[] d;
}
void Foo::print()
{
for (int i = 0; i < size; i++)
{
std::cout << d[i] << " ";
}
std::cout << std::endl;
}
Now I have a function func(Foo f) which does nothing.
void func(Foo f){}
int main()
{
Foo f(3);
f.print();
func(f);
Foo g(5);
f.print();
return 0;
}
Executing this code gives the following output:
0 3 6
0 5 10
Although I am printing f both times, somehow the values inside the array have changed.
I guess that the destructor of Foo is called on parameter Foo f after the execution of func(Foo f) and this frees the allocated memory for d, which is reallocated for Foo g(5). But how can I avoid this without using vectors or smart pointers?
The problem is with the design of the class. The default copy constructor will create a new instance of Foo when passed by value into the free standing function named func.
When the instance of Foo named f exits scope then the code invokes the user-provided destructor that deletes the array of doubles. This opens the code to the unfortunate situation of deleting the same array twice when the original instance of Foo named f exits scope at the end of the program.
When run on my machine, the code does not produce the same output. Instead I see two output lines of 0 3 6 followed by fault indicating the double free operation.
The solution is to avoid the copy by passing by reference (or by const reference): void func(Foo const &f) { } or to supply a valid copy constructor that makes a deep copy of the underlying array. Passing by reference is just a bandaid that avoids exercising the bug.
Using std::vector<double> fixes the problem because the default copy constructor will perform a deep copy and avoid double deallocation. This is absolutely the best approach in this small example, but it avoids having to understand the root of the problem. Most C++ developers will learn these techniques then promptly do what they can to avoid having to write code that manually allocates and deallocates memory.
You should probably pass the object as a reference func(Foo& f) or - if you do not want to modify it at all - as a constant reference func(const Foo& f). This will not create or delete any objects during the function call.
Aside from that, as others have already mentioned, your class should better implement the Rule of Three.
When you pass a value to a function, it is supposed to be copied. The destructor is run on the copy and should no effect on the original object. Foo fails to implement a copy constructor, so compiler provides the default one which simply performs a member-wise copy of the struct. As a result, the "copy" of Foo inside Func contains the same pointer as the original, and its destructor frees the data pointed to by both.
In order to be usable by idiomatic C++ code, Foo must implement at least a copy constructor and an assignment operator in addition to the destructor. The rule that these three come together is sometimes referred to as "the rule of three", and is mentioned in other answers.
Here is an (untested) example of what the constructors could look like:
Foo::Foo(const Foo& other) {
// copy constructor: construct Foo given another Foo
size = other->size;
d = new double[size];
std::copy(other->d, other->d + size, d);
}
Foo& Foo::operator=(const Foo& other) {
// assignment: reinitialize Foo with another Foo
if (this != &other) {
delete d;
size = other->size;
d = new double[size];
std::copy(other->d, other->d + size, d);
}
return *this;
}
Additionally, you can also modify functions like func to accept a reference to Foo or a constant reference to Foo to avoid unnecessary copying. Doing this alone would also happen fix the immediate problem you are having, but it would not help other issues, so you should definitely implement a proper copy constructor before doing anything else.
It's a good idea to get a good book on C++ where the rule of three and other C++ pitfalls are explained. Also, look into using STL containers such as std::vector as members. Since they implement the rule of three themselves, your class wouldn't need to.
One problem is that calling func creates a bitwise copy. When that copy goes out of scope the destructor is called which deletes your array.
You should change void func(Foo f){} to void func(Foo& f){}.
But better yet you add a create copy constructor or add a private declaration to stop it being called unexpectedly.

Destructors messing up in Dev-C++ and Code::Blocks

#include <iostream>
using namespace std;
class Exem {
int *a;
public:
Exem() { a = new int; *a = 0; };
Exem (int x) { a = new int; *a = x; };
~Exem () { delete a; };
int f (void);
Exem operator+ (Exem);
};
int Exem::f (void) {
return *a * 2;
}
Exem Exem::operator+ (Exem nimda) {
Exem aux;
*aux.a = *a + *nimda.a;
return aux;
}
int main() {
Exem adabo(1);
Exem inakos(2);
adabo = adabo + inakos;
cout << adabo.f();
cin.get();
}
This is my code, an example class made to showcase the problem. The output of main() would, in theory, be '6', but all that actually shows up are nonsensical numbers.
This apparently has to do with the class' destructor, which, from what I understood, get called too early at the end of the operator+ function - aux gets lost before it is actually passed. I came to such conclusion because ~Exem(), when commented, allows the program to execute as expected.
I'm guessing this has to do with these two compilers, because when I tried to compile the exact same code in Embarcadero RAD Studio it would work.
You need to explicitly define a copy constructor and assignment operator for Exem as you have a dynamically allocated member variable.
If a copy constructor and assignment operator are not explicitly defined for a class the compiler generates default versions of these, which are not suitable for a class that has dynamically allocated members. The reason the default generated versions are unsuitable is that they perform a shallow copy of the members. In the case of Exem, when an instance of it is copied more than one instance of Exem is pointing to the same dynamically allocated int member named a. When one of the instances is destroyed that a deleted, and leaves the other instance with a dangling pointer and undefined behaviour.
See the rule of three.
A simple fix for Exem would be change a from an int* to an int. The default copy constructor, assignment operator and destructor would be correct.
Note that Exem::operator+() should take a const Exem& parameter as it does not change its argument.

C++: Destructor being called before it should go out of scope?

I am having a problem with a destructor being called for a class at the end of a subroutine even though it should be defined outside of the scope of the subroutine.
Here is the smallest piece of code I have that displays my problem:
#include <iostream>
using namespace std;
class Foo {
private:
double *array;
public:
Foo(int N) {
array = new double[N];
for (int i=0; i<N; i++) {
array[i]=0;
}
}
~Foo() {
delete[] array;
}
};
void subroutine(Foo x) {
cout << "Hello!" << endl;
}
int main() {
Foo bar(10);
subroutine(bar);
subroutine(bar);
}
Now the destructor for the object bar here gets called after the first subroutine finishes even though it's scope should be the whole of the main() function? This means that when I call the second subroutine the destructor is called again and I get a memory leak.
I have found I can fix this by calling by reference in the subroutine but I am not very satisfied with this fix since I dont understand why it didn't work in the first place.
Can anyone shed some light on this for me?
Thanks.
You are passing a Foo by value to the subroutine function. This means it has it's own copy, which gets destroyed on exiting it's scope.
void subroutine(Foo x) {
// x is a new Foo here. It will get destroyed on exiting scope,
// resulting in a destructor call
}
Your main problem here is that you have not implemented a copy constructor, so the dynamically allocated array is not copied (only the pointer that points to it is). So, when you copy Foo objects, you have each copy referring to the same array. And each copy will try to destroy it.
You should follow the rule of three and implement an assignment operator and a copy constructor that make a "deep copy" of the array, such that each Foo object owns its own array.
You are passing bar by value to subroutine so a copy is being created. To avoid making a copy pass it by reference:
void subroutine(Foo& x)
{
cout << "Hello!" << endl;
}
You can prevent accidental copies of your class by declaring the copy constructor and copy assignment operator private like this:
class Foo {
private:
double *array;
Foo(const Foo&);
Foo& operator=(const foo&);
public:
...
};
Then you get a compilation error instead. If you really need to be able to make a copy of your class then you will actually need to implement these functions to perform a "deep copy" (or better yet use std::vector<float> and let that manage the memory for you including safe copying).
When you call void subroutine(Foo x) { your object bar is copied (thus destructor is called after function finishes).
Try using: void subroutine(Foo &x) {, it should work just fine.
The problem you're having is that you're passing your object by value:
void subroutine(Foo x) {
This is creating a temporary object and invoking the copy constructor/destructor of your object every time you call it.

Why can I allocate an array of objects but not put them in a vector?

I have a class that I want to contain multiple objects of something I created. Right now the code that works is:
process.h:
private:
myObj *data;
process.cc:
data = new myObj[10];
I would like to pass a value to the constructor however, so I tried to convert it to a std::vector (after modifying constructor to take a value).
process.h:
private:
std::vector<myObj> data;
process.cc:
for (int m=0; m<10; m++) data.push_back( myObj(1.2) );
When I try that it crashes upon execution with
*** glibc detected *** ... corrupted double-linked list: ... ***
And the backtrace in gdb shows an error in the destructor when I tried to free some memory for other arrays I allocated. A search didn't show up anything that was obvious. I am using a few static member variables in myObj, could that be an issue?
You are experiencing a double deletion bug. Consider this simple example:
struct Other {};
struct MyObj {
Other *p;
MyObj () : p(new Other) {}
~MyObj () { delete p; }
};
std::vector<MyObj> data;
data.push_back(MyObj());
The temporary object that is pushed onto data is stored properly. However, since it is a temporary, it is destroyed right after the push. This means, the p member is deleted when the temporary is destroyed, so the vector's version of the copy has a dangling pointer. When the vector object is destroyed, the pointer will be deleted again, resulting in a corrupted heap. The error message you received was from the glibc code complaining about the resulting bad state.
To fix this problem, a proper copy constructor should be defined, to pass ownership of the objects from the temporary to the destination. The rule of three says we should define the assignment operator as well.
struct MyObj {
mutable Other *p;
MyObj () : p(new Other) {}
MyObj (const MyObj &o) : p(o.p) { o.p = 0; }
~MyObj () { delete p; }
const MyObj & operator = (MyObj o) {
using namespace std;
swap(*this, o);
return *this;
}
};
The use of mutable is required to be able to modify the p member when the instance is const, and const was needed because temporaries are being passed in to the copy constructor. With this change, pushing items into the vector work fine.
A better solution would be to define p to use a unique_ptr instead.
struct MyObj {
std::unique_ptr<Other> p;
MyObj () : p(new Other) {}
};
No destructor is needed in this example, since the default destructor will destruct p, which will cause the Other instance to be deleted by unique_ptr.
You're trying to use a vector to store multiple objects within a class? I have run into this problem also and the only way I could fix this was to place the function you are using the vector in, in the header. What I believe is happening is you're providing the vector with a type, in this case, myObj, but the .cpp can not see what type you've defined the vector as. So sticking the function inside the Header seems to fix it. I believe there are other ways around this but I've not looked into the problem much.
example code:
class A
{
private:
vector<myObj> data;
public:
A();
~A();
printData()
{
for(int i = 0; i < data.size(); i++)
{
printf("X position: %.2f Y position: %.2f Z position: %.2f \n", data.at(i).x, data.at(i).y, data.at(i).z);
}
};
}
This may be the problem, or, it is your naming convention. I am not sure what you are doing but how does data *myObj; and data = new myObj[10]; actually work? Wouldn't it be myObj = new data[10]? If so then your vector would be:
vector<data> myObj;

Side effects when passing objects to function in C++

I have read in C++ : The Complete Reference book the following
Even though objects are passed to functions by means of the normal
call-by-value parameter passing mechanism, which, in theory, protects
and insulates the calling argument, it is still possible for a side
effect to occur that may affect, or even damage, the object used as an
argument. For example, if an object used as an argument allocates
memory and frees that memory when it is destroyed, then its local copy
inside the function will free the same memory when its destructor is
called. This will leave the original object damaged and effectively
useless.
I do not really understand how the side effect occurs. Could anybody help me understand this with an example ?
Here is an example:
class bad_design
{
public:
bad_design( std::size_t size )
: _buffer( new char[ size ] )
{}
~bad_design()
{
delete[] _buffer;
}
private:
char* _buffer;
};
Note that the class has a constructor and a destructor to handle the _buffer resource. It would also need a proper copy-constructor and assignment operator, but is such a bad design that it wasn't added. The compiler will fill those with the default implementation, that just copies the pointer _buffer.
When calling a function:
void f( bad_design havoc ){ ... }
the copy constructor of bad_design is invoked, which will create a new object pointing to the same buffer than the one passed as an argument. As the function returns, the local copy destructor will be invoked which will delete the resources pointed by the variable used as an argument. Note that the same thing happens when doing any copy construction:
bad_design first( 512 );
bad_design error( first );
bad_design error_as_well = first;
That passage is probably talking about this situation:
class A {
int *p;
public:
A () : p(new int[100]) {}
// default copy constructor and assignment
~A() { delete[] p; }
};
Now A object is used as pass by value:
void bar(A copy)
{
// do something
// copy.~A() called which deallocates copy.p
}
void foo ()
{
A a; // a.p is allocated
bar(a); // a.p was shallow copied and deallocated at the end of 'bar()'
// again a.~A() is called and a.p is deallocated ... undefined behavior
}
Here is another example. The point is that when the callee (SomeFunc) parameter destructor is invoked it will free the same object (ptr) pointed to by the caller argument (obj1). Consequently, any use of the caller argument (obj1) after the invocation will produce a segfault.
#include <iostream>
using namespace std;
class Foo {
public:
int *ptr;
Foo (int i) {
ptr = new int(i);
}
~Foo() {
cout << "Destructor called.\n" << endl;
//delete ptr;
}
int PrintVal() {
cout << *ptr;
return *ptr;
}
};
void SomeFunc(Foo obj2) {
int x = obj2.PrintVal();
} // here obj2 destructor will be invoked and it will free the "ptr" pointer.
int main() {
Foo obj1 = 15;
SomeFunc(obj1);
// at this point the "ptr" pointer is already gone.
obj1.PrintVal();
}