1

If I have a class with members like this:

class MyClass {
public:
    void set_my_vector() {
        for (int ind = 0; ind < 3; ++ind) {
            my_vector.push_back(new MyStruct(i, i*2));
        }
    }
private:
    struct MyStruct {
        int num_a;
        int num_b;
        MyStruct(int i, int j) : num_a(i), num_b(j) {}
    };
    std::vector<MyStruct*> my_vector;
};

Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?

EDIT: The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v

#include <iostream>
#include <vector>

class MyClass {
public:    
    void fill_my_vector(int i, int j) {
        my_vector.clear();
        for (int ind = 0; ind < 3; ++ind) {
            my_vector.push_back(new MyStruct(i, j));
        }
    }

    void print () {
        for (int ind = 0; ind < 3; ++ind) {
            std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
        }
        std::cout << std::endl;
    }
private:
    struct MyStruct {
        MyStruct (int i, int j) :
        int1(i), int2(j)
        {}
    
        int int1;
        int int2;
    };

    std::vector<MyStruct*> my_vector;
};

int main()
{
    MyClass my_class1;
    my_class1.fill_my_vector(42, 43);

    std::cout << "my_class1: " << std::endl;
    my_class1.print();

    MyClass my_class2 = my_class1;
    my_class2.fill_my_vector(12, 13);

    std::cout << "my_class2: " << std::endl;
    my_class2.print();

    std::cout << "my_class1: " << std::endl;
    my_class1.print();

}

EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.

user_185051
  • 426
  • 5
  • 19
  • As you surmised, and your recent edit has confirmed, a `vector` copies its elements for you. If those elements happen to be pointers to other objects, you're on your own. The addresses are copied, because they are the values of the elements, not the pointed-at objects. Whether you need Rule of Three/Five protection depends on who [owns](https://stackoverflow.com/questions/49024982/what-is-ownership-of-resources-or-pointers) those pointed-at objects. In this case it looks like you probably need at least Rule of Three. – user4581301 Sep 08 '20 at 04:49
  • But if only the pointers are copied, then after ```MyClass my_class2 = my_class1;``` and ```my_class2.fill_my_vector(12, 13);```, I assume that ```my_class1. my_vector ``` will also have elements (12, 13) . But it has elements (42, 43), why? – user_185051 Sep 08 '20 at 04:52
  • 1
    You've conflated the pointers with the objects they point at. A pointer is an object that just happens to hold the address of another object. Here the pointers have been copied and initially both copies point at the same place. You could point one of the pointers somewhere else and have two pointers to different objects, but in this case `my_class2`'s `vector` is cleared-- no pointers whatsoever anymore--and filled with completely new pointers pointing at completely new objects. There is no longer any connection between the two `my_class`s. – user4581301 Sep 08 '20 at 05:02
  • 1
    Recommendation: Sit down and draw some pictures of who is pointing at what and when to help yourself visualize what's happening. – user4581301 Sep 08 '20 at 05:04
  • Oh, I see, makes sense. Thank you, @user4581301. – user_185051 Sep 08 '20 at 05:05

2 Answers2

2

You need to implement the copy constructor, copy assignment and destructor.

Additionally, consider changing your vector declaration from

std::vector<MyStruct*> my_vector;

to

std::vector<std::unique_ptr<MyStruct>> my_vector;

so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.

Tanveer Badar
  • 5,438
  • 2
  • 27
  • 32
  • Could you add more details according to my edit to the original post? What exactly happens if I use e.g. default copy constructor? – user_185051 Sep 08 '20 at 04:42
1

No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:

  • Store MyStruct by value.
  • Store std::unique_ptr<MyStruct>.
  • Store std::shared_ptr<MyStruct>.

Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.

ivan.ukr
  • 2,853
  • 1
  • 23
  • 41
  • If the ```std::vector``` will not take care of the deep copying, then why "default implementation which compiler will generate automatically will be good enough"? I assume the default implementation will do shallow copy for vector's elements, is it not the case? – user_185051 Sep 08 '20 at 17:05
  • 1
    Copy constructors, assignment and destructor are only required when you maintain some non-trivial state inside the class, like if you have there pointer to some object and so you have to copy that object when you create new object from this or assign. Member variables of primitive numeric types like int, double, etc. can be copied bit-by-bit, this is what compiler does by default, so it is good enough. – ivan.ukr Sep 09 '20 at 08:34