The problem is that in the copy constructor of Boo
you're dereferencing a nullptr
. This is because when you wrote:
std::vector<Boo> vec(1); //this creates a vector of size 1 using Boo's default constrcutor
This is what happens due to the above statement:
- The above statement creates a vector named
vec
of size 1
using Boo
's default constructor.
- This means that there is already
1
Boo
object inside vec
. Moreover since this Boo
object was created using the default constructor, its fptr
is set to nullptr
.
Now, when you wrote:
vec.push_back(b);// this adds/push_back object b onto the vector vec so that now its size will be 2
Now, these are the important things that you have to note here:
- The vector
vec
has already 1
Boo
object inside it which has its fptr
as nullptr
.
- Now you're adding one more element
b
into the vector, due to which reallocation may happen. And if/when this reallocation happens, the copy constructor of Boo
will be used.
- And when this copy constructor is used to copy the already present
Boo
object, it dereferences its fptr
. But since that fptr
is nullptr
and we know that dereferencing a nullptr
is undefined behavior, so this may cause the program to segmentation fault as in your case.
Solution
First, before dereferencing fptr
you should check it is a null pointer or not.
Second, you must free the memory you allocated via new
using delete
. This can be done by adding a destructor for class Boo
and using delete
on fptr
inside it.
If you don't free this memory then you will have memory leak in your program.
#include <iostream>
#include <vector>
struct Foo
{
int i;
double d;
};
class Boo
{
public:
Boo() : fptr(nullptr)
{
std::cout << "Boo default construct..." << std::endl;
}
Boo(int i, double d):fptr(new Foo{i,d})
{
std::cout <<"Boo parameterized const"<<std::endl;
}
Boo(const Boo &rhs)
{
std::cout <<"Boo copy const"<<std::endl;
//add a check before dereferencing
if(rhs.fptr!= nullptr)
{
fptr = new Foo{rhs.fptr->i,rhs.fptr->d};
std::cout<<"i: "<<rhs.fptr->i <<" d: "<<rhs.fptr->d<<std::endl;
}
else
{
std::cout<<"nullptr found"<<std::endl;
}
}
Foo *fptr;
//add destructor
~Boo()
{
std::cout<<"Boo destructor"<<std::endl;
//for debugging check if we got a null pointer
if(fptr!=nullptr) //just a check before deleting, you can remove this. This is for printing(debugging) when we get a nullptr
{
delete fptr;
fptr = nullptr;
std::cout<<"delete done"<<std::endl;
}
else
{
std::cout<<"null pointer found while delete"<<std::endl;
}
}
};
int main(int argc, char const *argv[])
{
std::vector<Boo> vec(1);
Boo b(42, 10.24);
vec.push_back(b);
return 0;
}