0

I have a "twisted" question... Suppose to have a class like

class MyClass {
public:
 MyClass();
 ~MyClass();
MyClass& operator=(const MyClass& obj); 
private:
  int* mem;
};

where basically MyClass inits somehow mem (with a new call), the ~MyClass() deallocates mem with the delete operator. Suppose moreover the operator = is overloaded with the code

MyClass& operator=(const MyClass& obj) {
 if(this != &obj) {
   //allocate memory of "this" with the "new" operator and copy "obj" data;
 }
return *this;
}

my question is basically the following... With the following sequence of statements

//statement 1 for short
MyClass my_obj = some_obj_of_MyClass;

i guess everything is fine since the operator = allocates memory and copies the data, but with the following

//statement 2 for short
MyClass obj; //allocate memory for "mem" 
obj = some_obj_of_MyClass;

if think it is not correct the implementation i proposed since i don't delete memory allocated early. I could call the destructor inside the assignment operator block, but in that case probably the statement 1 wouldn't be safe.

So what it is a safe way to implement everything? I guess the problem here can be to understand when the destructor is called or how to implement it properly.

user8469759
  • 2,522
  • 6
  • 26
  • 50
  • 2
    Your first example uses the copy constructor, not `operator=`. In `operator=` it's guaranteed that `this` refers to an already-constructed object. – melpomene Jul 18 '15 at 19:06
  • 2
    `//statement 1` runs a (compiler-generated) copy constructor, *not* a (user-defined) assignment operator. It'll just set `my_obj.mem` to the same value as `some_obj_of_MyClass.mem`, so you'll have two objects pointing to the same memory, and eventually double destruction. So no, it's not fine. See also: [Rule of Three](https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)) – Igor Tandetnik Jul 18 '15 at 19:06
  • Is `//statement 1` equivalent to `MyClass obj(some_obj_of_MyClass)`? – user8469759 Jul 18 '15 at 19:10
  • either use smart pointers(unique_ptr or shared_ptr), or just call delete inside the assignment operator – Creris Jul 18 '15 at 19:29

1 Answers1

0

Your code violates the rule of three: Whenever a class provides a custom

  1. copy constructor
  2. copy assignment operator
  3. destructor

it should likely provide all three. Because, if any of these is omitted, it is possible to construct use cases where bad things happen. For example, contrary to intuition, the statement

MyClass my_obj = some_obj_of_MyClass;

does not call the assignment operator. It calls the copy constructor, which you have not provided. As such, the default copy constructor is used which simply copies the pointer. Once either my_obj or some_obj_of_MyClass is destructed, the other will have a pointer to the deleted memory region.

On the other hand, the statements

MyClass obj;
obj = some_obj_of_MyClass;

will first default construct obj, and then call the assignment operator on it. The assignment operator must be written in a way that it works correctly in every possible state of obj (i. e. it must not leak memory or double delete memory). That is, if obj.mem is allocated, the assignment operator must either reuse that memory or deallocate it (possibly replacing it with a new allocation). If obj.mem can be a null pointer, then the assignment operator must include special handling of this special case.

So, your choice is basically, whether you want to allow the mem pointer to become a null pointer, If you don't allow this, your default constructor must allocate a dummy memory region that can be deallocated by the assignment operator.


You can also work around the rule of three by deleting the unimplemented functions. Your class could be declared like this:

class MyClass {
public:
    MyClass();
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass& obj); 
    ~MyClass();
private:
    int* mem;
};

This would disallow the statement

MyClass my_obj = some_obj_of_MyClass;

forcing user code to use the more verbose

MyClass obj;
obj = some_obj_of_MyClass;

but which makes the implementation of MyClass a bit simpler.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106