2

I am a C++ newbie. I learned that a function can return by value, but in my code it doesn't seem to work right.

#include "pch.h"
#include <iostream>

class B {
public:
  int* ip;
  B() : ip(new int(0)) {}
  //COPY CTOR
  B(B& other){
    ip = new int(0);
    *ip = *other.ip;

  }
  //MOVE CTOR
  B(B&& other) : ip(NULL){
    ip = other.ip;
  }
  B& operator=(B& other)
  {
    int* ptr = new int(0);
    *ptr = *other.ip;
    delete ip;
    ip = ptr;
  }
  B& operator=(B&& other)
  {
    int* ptr = new int(0);
    *ptr = std::move(*other.ip);
    delete ip;
    ip = ptr;
  }
  ~B() { 
    delete ip; 
    ip = NULL; 
  }
};

B CreateB()
{
    B b;
   *(b.ip) = 99;
   return b;
}
int main()
{
    B BObj(CreateB());
    std::cout << "B.ip=" << *BObj.ip << std::endl;
    system("pause");
    return 0;
}

I used visual studio 2019 in debug mode, I stepped in CreateB() and found local object B created. At "return b;" statement debug stepped to Move Constructor B(B&& other) which I figured out this is compiler optimization. Instead of using Copy constructor to create B object from local B object the compiler used Move Constructor. However, after executing Move constructor, debug took me to destructor ~B(). Now the object returned by the function to main was gone. Why didn't the compiler use Copy Ctor then deleted the local object? Thanks!

inflator
  • 39
  • 4
  • 2
    The move constructor is wrong, it makes both objects share the same allocated object (the correct behaviour would be for the new object to take over the allocated object) – M.M Oct 02 '19 at 01:44
  • Also you should make the copy constructor and copy assignment operators take by const reference – M.M Oct 02 '19 at 01:45
  • 1
    @paulsm4 that part is fine, it is OK to return a local variable by value – M.M Oct 02 '19 at 01:45
  • 1
    @paulsm4 it's always been that way (in C and C++), the local variable is (conceptually) copied to the return value object before the local variable is destroyed – M.M Oct 02 '19 at 01:51

1 Answers1

3

Why didn't the compiler use Copy Ctor then deleted the local object?

Because, as you observed, it used the move constructor instead. The move constructor was called, then the local object was destroyed. (Destructors are called when an object goes out of scope, even if that object had been moved from.)

When the local object was destroyed, the thing that its ip member pointed to was deleted. This is normally good, except that the moved object pointed to the same thing. You probably want to have your move constructor set other.ip to some valid value. (I would normally suggest nullptr, but it looks like your class assumes ip is never null.)

For example:

B(B&& other) : ip(other.ip){
    other.ip = new int(0);
}
JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • Thank you! I set other.ip=NULL; this makes sense. But the original code although failed to work in VS it worked in Linux. Any idea? Thanks – inflator Oct 02 '19 at 09:37
  • @inflator The original code invoked undefined behavior, which means result are not guaranteed to be consistent. The [hotel room answer](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794) is applicable to your situation. (That answer was to a question about local variables, but the same principles apply to your original code.) – JaMiT Oct 02 '19 at 21:45