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

#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.

Related

Default size of an int variable, when an object is created?

class Vect {
public:
Vect(int n);
~Vect();
Vect(const Vect& original);
private:
int* data;
int size;
};
Vect::Vect(int n) {
size = n;
data = new int[n];
}
Vect::~Vect() {
delete [] data;
}
Vect::Vect(const Vect& original) {
size = original.size;
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = original.data[i];
}
}
#include <bits/stdc++.h>
using namespace std;
int main(void) {
Vect a(100);
Vect b = a;
Vect c;
c = a;
return 0;
}
I have a Vect class now, in main I created a Vect object that variable c holds, what will be the default size of c.size ??
Or It won't have any default?
If it does not have a default value then how does b have 100 (as in a.size is now equals b.size)?
What will be the default size of c.size ??
There is no default value except if you provide one. You should have a default constructor if you want to cover it (otherwise using uninitialized variable is undefined behaviour).
For example:
Vect::Vect() : data(nullptr), size(0)
{}
If it does not have a default value then how does b have 100 ?
Actually, when you write Vect b = a;, it is equivalent as Vect b(a);. In other words, the copy constructor is called (this is copy-initialization).
However, when you write:
Vect c;
c = a;
This is a copy-assignment. And you didn't provide one which is a problem because you need to handle the dynamic allocation of the data member (prevent self-assignment, deallocate if not nullptr and then reallocate with the new content), etc...
You should define the operator=() for the Vect class for your program to be well-formed.
To answer your question: There is no default value of Vect::size unless you provide a default one in the class declaration, like
int size = 0;
If you do not initialize Vect::size you incur in undefined behavior.
Further, this code has a lot of problems, and in fact it does not compile.
Essential problems:
There is no constructor of Vect with no parameters, and there is not implicitly declared default constructor because you define Vect::Vect(int n). Hence the line Vect c; cannot compile.
The code c = a does not call your copy constructor Vect::Vect(const Vect& original), because the variable c already exists (assuming you have fixed the problem above). It does, instead, call the implicitly defined copy assignment operator, which you have not explicitly defined. This however just copies the member variables, thus it does not have the "right" logic since, after such a copy, both c.data and a.data point to the same area of memory. They are not a "copy", and so when a and c go out of scope, the allocated memory is freed twice (crashing the program).
You need to define a correct copy-assignment operator Vect::operator=.
Other points:
Do not use using namespace std
Do not include <bits/stdc++.h>

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.

Assign class constructor to a new constructor with parameter in C++

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.

could you tell me why does this code crash?

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) {
...
}

Malloc on a struct containing a std::vector

Here is the situation :
I use a malloc to allocate memory for a struct.
The struct contains various items such as pointers, string variables and vectors.
The fact is, when we use malloc, no constructors are called. Using a code similar to the following one, I've experienced some situation where some variables worked while others didn't.
Note : The following code doesn't compile. It's purpose is only to illustrate the situation.
struct MyStruct
{
MyClass* mFirstClass;
bool mBool;
std::string mString;
std::vector<MyClass> mVector;
};
int main()
{
MyStruct* wMyStructure;
wMyStructure = (MyStruct*) malloc (sizeof(MyStruct));
MyClass wMyClassObject;
wMyStructure->mFirstClass = new MyClass();
wMyStructure->mFirstClass->func();
wMyStructure->mBool = false;
wMyStructure->mString = "aString";
wMyStructure->mVector.push_back(wMyClassObject);
return 0;
}
By using pointers instead of those variables (std::string* mString), followed by a call to the object constructor (mString = new std::string;) Exception are not thrown.
However, I've experienced a situation where the mString was used without problem without the constructor being called, but when it came to the vector, the application exit automatically.
This left me with many questions:
When will an object throw an exception if no constructor were used?
In the situation I experienced, only the vector caused problem. Could mString be left as it is or should I call it's constructor?
What would be the safest way, using malloc, to do the whole thing?
Using object without constructing it must be an undefined behaviour. Anything may happen at any moment. If you do this, you must not rely on any part of your code to run smoothly, because the language doesn't guarantee anything in this case.
Your code causes undefined behaviour, because your wMyStructure does not point to an object, so you may not use the accessor operator -> on it.
An object only commences its life after its constructor has completed. Since you don't call any constructor, you do not have an object.
(If your struct were a POD, i.e. just consisting of primitive types and PODs, then this would be OK, because PODs have trivial constructors, which do nothing.)
The concrete problem you're facing is that the string and vector members of your struct didn't get to call their constructors, so those members don't exists, and hence the entire object doesn't.
If you want to decouple memory management from object construction, you can use placement syntax:
// get some memory
char arena[HUGE_VAL];
void * morespace = malloc(HUGE_VAL);
// construct some objects
MyClass * px = new (arena + 2000) MyClass; // default constructor
YourClass * py = new (morespace + 5000) YourClass(1, -.5, 'x'); // non-default constructor
(You have to destroy those objects manually, px->~MyClass(); etc., when you're done with them.)
It is undefined behaviour to use a non-initialized object. Exception may be thrown at any time- or not at all.
1 ) When will an object throw an exception if no constructor were used ?
If you don't call the constructor, there is no object. You have just allocated some space.
2 ) In the situation I experienced, only the vector caused problem. Could mString be left as it is or should I call it's constructor ?
This is all undefined behavior, just about anything could happen. There are no rules.
3 ) What would be the safest way, using malloc, to do the whole thing ?
The safest way would be not to use malloc, but allocate using new that will call constructors. It is as simple as this
MyStruct* wMyStructure = new MyStruct;
None of the other answers appear to explain what the compiler is doing. I'll try to explain.
When you call malloc the program reserve some memory space for the struct. That space is filled with memory garbage, (i.e. random numbers in place of the struct fields).
Now consider this code:
// (tested on g++ 5.1.0 on linux)
#include <iostream>
#include <stdlib.h>
struct S {
int a;
};
int main() {
S* s = (S*)malloc(sizeof(S));
s->a = 10;
*((int*)s) = 20;
std::cout << s->a << std::endl; // 20
}
So when accessing a member of a struct you are actually accessing a memory position, there should be no unexpected behavior when writing to it.
But in C++ you can overload operators. Now imagine what would happen if the overloaded assignment operator need the class to be initialized, like in the code below:
// (tested on g++ 5.1.0 on linux)
#include <iostream>
#include <stdlib.h>
class C {
public:
int answer;
int n;
C(int n) { this->n = n; this->answer = 42; }
C& operator=(const C& rhs) {
if(answer != 42) throw "ERROR";
this->n = rhs.n; return *this;
}
};
struct S {
int a;
C c;
};
int main() {
S* s = (S*)malloc(sizeof(S));
C c(10);
C c2(20);
c = c2; // OK
std::cout << c.n << std::endl; // 20
s->c = c; // Not OK
// Throw "ERROR"
std::cout << s->c.n << std::endl; // 20
}
When s->c = c is executed the assignment operator verifies if s->c.answer is 42, if its not it will throw an error.
So you can only do as you did in your example if you know that the overloaded assignment operator of the class std::vector does not expect an initialized vector. I have never read the source code of this class, but I bet it expects.
So its not advisable to do this, but its not impossible to be done with safety if you really need. You just need to be sure you know the behavior of all assignment operators you are using.
In your example, if you really need an std::vector on the struct you can use a vector pointer:
class MyClass { ... };
struct S {
std::vector<MyClass>* vec;
}
int main() {
S s;
MyClass c;
s.vec = new std::vector<MyClass>();
s.vec->push_back(c);
}