smart pointer , dynamically allocated memory, copy constructor and assignment operator

Hello forum,

I believe that it is a customary that you should write your own copy constructor and assignment operator to provide deep copy of the memory whenever you have dynamically allocated memory in the class. How does it change if someone decides to use smart pointer instead of raw pointer ?

Thanks
That depends on the pointer. The default implementations simply copy construct/assign.

Therefore, if the smart pointer's copy methods perform deep copy, then you are ready. However, if they do not, then you have to write the methods.


There is also the destructor to consider. On that the smart pointers are more likely to do the Right Thing by default.


Since C++11 there are new players on the field: the move constructor and the move assignment. More fun.
you should write your own copy constructor and assignment operator to provide deep copy of the memory whenever you have dynamically allocated memory in the class

Yeah, if you have a class that has a pointer which manages memory you have to write your own:
- destructor
- copy-ctor
- move-ctor
- copy-assignment operator
- move-assignment operator
if you write one of them then the compiler knows that he has to be carefully with the class and won't automatically create the rest.

How does it change if someone decides to use smart pointer instead of raw pointer ?

you should not need to implement them when using smart pointer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Example program
#include <iostream>
#include <string>
#include <memory>

class A { /* ... */ };

class B {
public:
    std::shared_ptr<A> a;
    
    B() : a(0) {}
    B(std::shared_ptr<A> p) : a(p) {}
};

int main()
{ 
    int i = 0;
    
    B b0(std::make_shared<A>()); // ctor
    B b1 = b0; // copy ctor 
    
    // both point to the same location
    std::cout << "Part " << ++i << std::endl;
    std::cout << "b0: " << b0.a.get() << std::endl;
    std::cout << "b1: " << b1.a.get() << std::endl;
    
    B b2(std::move(b1)); // move ctor  
    // b2 and b1 switched
    std::cout << "\nPart " << ++i << std::endl;
    std::cout << "b0: " << b0.a.get() << std::endl;
    std::cout << "b1: " << b1.a.get() << std::endl;
    std::cout << "b2: " << b2.a.get() << std::endl;
    
    b1 = b2; // copy assignment -> b1.a points to the same as b2.a
    B b3;
    b3 = std::move(b2); // move assignment -> b3 = b2 and then b2 is 0

    std::cout << "\nPart " << ++i << std::endl;
    std::cout << "b0: " << b0.a.get() << std::endl;
    std::cout << "b1: " << b1.a.get() << std::endl;
    std::cout << "b2: " << b2.a.get() << std::endl;
    std::cout << "b3: " << b3.a.get() << std::endl;
}
Last edited on
How does the concept of deep copy fit in on the above sample code ? I can see that that move semantics is doing the shallow copy. Consider the following sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A {};

class B
{
    std::vector<std::shared_ptr<A>> mPtrVec;
    mInitialSize;
    public:
       B(int n = 10) : mInitialSize(n) 
       {
              for(unsigned int = 0; i < mInitialSize ; ++i)
              {
                  mPtrVec.push_back(std::shared_ptr<A>(new A));
              }
       };

       ~B() { mPtrVec.clear();}
      
};


The above snippet does not contain the copy constructor, assignment operator. In that case the C++ standard will provide the default ones and it will make the shallow copy here and it will not be correct, as it will point to the same memory. If I write the copy constructor and assignment operator, then I have make the copy of the memory as well, not just the memory pointer. This the very C++ concept, I believe. What I do not got yet is that how come the move semantics in C++11 standard can ease the process that I have just described .

It will be nice if you use the above reference sample as further explanation over this issue.


Thanks
oh yeah, true, I'm sorry, in my example there is no deep copy.

I can see that that move semantics is doing the shallow copy. Consider the following sample:
nah, the move semantics transfers the ownership of the data from one object to the other. basically the pointer of the new object is set to the data from the old and the old is set to nullptr


Do you allways want B-objects to have a vector of A's for themselves without any other objects acessing them?
- if yes: simply don't use pointers, just store the data in a vector of A's
otherwise you have to better describe the behaviour you want.

If you only want deep copies don't use pointers
if you only want shallow copies only use shared_ptrs
if you want both of them you have to be more preciese about when you want to do what.

I found many developers abusing pointers because they thought "it would be better to have the memory managed by pointers so they can easily be shared" but that often resulted in bad code.
Last edited on
Topic archived. No new replies allowed.