0

I have recently started learning move semantics and shared pointers, and I am having a lot of difficulty trying to understand it.

I am currently taking a course on these topics, but the instructor did not explain why these constructors and destructors are called when we swap the values contained in the pointers. The calls to swap in the shared pointer (as in b.swap(a)) and the std::swap(a, b) are not calling any constructors or destructor, while the call to std::swap(*a, *b) are calling a bunch of them.

The main code:

int main(int argc, char** argv){

    std::shared_ptr<strc> a = std::make_shared<strc>("one");
    std::shared_ptr<strc> b = std::make_shared<strc>("two");

    message("b.swap(a)"); // No constructors or destructors are called.
    b.swap(a);
    disp(a);
    disp(b);

    message("std::swap"); // A bunch of constructors and destructors are called.
    std::swap(*a, *b);
    disp(a);
    disp(b);

    message("std::swap"); // No constructor or destructors are called.
    std::swap(a, b);
    disp(a);
    disp(b);

    return 0;
}

The implemented class for "strc" is (I am just going to show the 'important' implementations in it for the sake of conciseness):

strc::strc(strc && o){
    msg("Move Constructor.");
    this->data = std::move(o.data);
    o.data = nullptr;
}

strc::~strc(){
    msg("Destructor.");
    delete [] data;
}

strc & strc::operator = (strc o){
    msg("Copy and Swap (=).");
    swap(o);
    return *this;
}

void strc::swap(strc & o){
    msg("Calling std::swap");
    std::swap(this->data, o.data);
}

This is what is being printed to the console (For me to understand more about what is happening and have a thorough understanding of move semantics and shared pointers).

Call to b.swap(a) one (1) two (1)

Call to std::swap(*a, *b) strc: Move Constructor. strc: Move Constructor. strc: Copy and Swap (=). strc: Calling std::swap strc: Destructor. strc: Move Constructor. strc: Copy and Swap (=). strc: Calling std::swap strc: Destructor. strc: Destructor. two (1) one (1)

Call to std::swap(a, b) one (1) two (1)

Why is that? Does it have to do with the move semantics? Shouldn't it be calling the standard swap function? I cannot understand the difference between these swap calls, and why one of them is calling all of these constructors and destructor.

maufcost
  • 169
  • 11
  • It could help if you tried to write a shared_ptr class yourself. It might make it more obvious why, when calling `swap(*a,*b)`, the surrounding shared_ptr is irrelevant. – Marc Glisse Mar 04 '18 at 12:51

1 Answers1

1
  1. b.swap(a) swaps pointers.
  2. std::swap(*a, *b) swaps contents of pointed objects.
  3. std::swap(a, b) swaps pointers again.

Move constructors are used in the case 2. It is what they are for.

Move constructors are used in the case 1 and 3 too, but you do not observe this since you did not modify std::shared_ptr constructors.

You can learn more here Should the Copy-and-Swap Idiom become the Copy-and-Move Idiom in C++11?

273K
  • 29,503
  • 10
  • 41
  • 64
  • I understood what you mean! Just in regard to what I am having in my console: Two move contructors are called. That means that two copies are made for the swap function to work with, right? Then, it prints "Copy and Swap (=)". Why is that? Why is my '=' overload function being called? After it, a single destructor is called. I cannot understand clearly what's happening behind the scene. After this single destructor is called, it is called again another move constructor, and then it prints "Copy and Swap(=)" again, and delete two more destructors. – maufcost Mar 04 '18 at 14:32
  • Read this article https://stackoverflow.com/questions/25286544/how-does-the-standard-library-implement-stdswap You did not provide move assignment operators, `t1 = ` and `t2 = ` use generic assignment operators. Move constructor is used in `t1 = std::move(t2)` only. – 273K Mar 04 '18 at 15:06