0

I am new to code in C++. So, below code looks pretty decent to me.

#include<iostream>

using namespace std;

class B {};

class A {
    public: 
    B* b;

    A() {
        cout << "ctor" << endl;
        b = new B();
    }

    ~A() {
        cout << "dtor" << endl;
        delete b;
    }
};

void func(A a) {
    cout << a.b << endl;
}

int main() {
    A a;
    cout << a.b << endl;
    func(a);
    cout << a.b << endl;
}

But I found an issue with this code. When I run this, it gives free(): double free detected in tcache 2 error. I know the cause of this error (it is because dtor is being called 2 times).

One way to solve the problem is, writing a copy constructor for class A where, I create a new B() like this.

A(A const& a) {
    cout << "copy ctor" << endl;
    b = new B();
    *b = *a.b;
}

But if B is a very big class, and hence if I prefer to share b pointer, then how would I avoid this problem?

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35
  • 1
    You need to follow [the rule of three, five or zero](https://en.cppreference.com/w/cpp/language/rule_of_three). – Some programmer dude Jul 03 '21 at 06:31
  • 1
    If you don't want to copy, then I recommend the rule of zero together with using the ownership semantics of [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr). – Some programmer dude Jul 03 '21 at 06:32
  • Thanks for that rule of three.. I think, I should be using rule of three with private copy constructor. ? – Sourav Kannantha B Jul 03 '21 at 06:36
  • If you want to implement it yourself, [`= delete;`](https://stackoverflow.com/questions/5513881/meaning-of-delete-after-function-declaration) copies and implement moves. – Evg Jul 03 '21 at 06:40
  • 1
    @SouravKannanthaB If you want shared ownership and want to avoid copying the pointed object, then you should use std::shared_ptr as suggested. You won't need any copy constructor nor destructor. – eerorika Jul 03 '21 at 06:41
  • @SouravKannanthaB -- *But if B is a very big class, and hence if I prefer to share b pointer* -- If you really wanted to do that, you wouldn't have written `void func(A a)`. This passes `A` by value -- a copy is going to be made. You would have used reference instead. This is a case of not wanting to do something, but doing it anyway. – PaulMcKenzie Jul 03 '21 at 07:54
  • @Paul Suppose if user of class A doesn't know about class B, then he may write void func(A a). In this case, somehow owner of class must avoid large copying of class B. So I asked. Anyways I got it, by declaring copy ctor = delete. This would give a compile time error when user does that. – Sourav Kannantha B Jul 03 '21 at 08:01
  • @SouravKannanthaB *Suppose if user of class A doesn't know about class B, then he may write void func(A a)* -- No, a better interface is to have the parameter a (const) reference. Look at [std::vector::push_back](https://en.cppreference.com/w/cpp/container/vector/push_back). A `vector` is a template, so has no prior knowledge of what objects are going to be used -- the object could be 1 byte or 1000 bytes, but the parameter is passed by reference (r-value, l-value). – PaulMcKenzie Jul 03 '21 at 08:04

0 Answers0