-1

I am trying to implement copy and move assignments, but I don't understand how should I use them. I have read the following topic
When did copy assignment operator called?
But it did not work for me.

Class:

class Directory{

    string name;
public:
        Directory(string name):name(name) {

        }
        ~Directory() {
            cout << "Deleting was called" <<endl;

            }

        Directory& operator=(Directory& other){
            cout << "cp assigment" <<endl;
            return *this;
        }
        Directory& operator=(Directory&& other){
            cout << "move assigment" <<endl;
            return *this;
        }
};

Main

int main()
{

    Directory* dir = new Directory("alex");
    Directory* dir2;
    dir = dir2;

    cout<<"done"<<endl;
};

I would like to know when the copy assignment and move assignment are called. Thanks in advance.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Alex Lavriv
  • 321
  • 1
  • 10
  • The assignment is done for pointers (`Directory*`) in your case. Remove the `*`s and the `new` and it will work. – Scheff's Cat Nov 18 '17 at 07:38
  • 1
    You are working with pointers, how would you expect copy would be called?? – user0042 Nov 18 '17 at 07:38
  • 1
    `dir = dir2;` invokes built-in pointer copy assignment operator, not your class copy assignment operator. – user7860670 Nov 18 '17 at 07:38
  • 1
    Btw. `dir2` is uninitialized. Hence, after `dir = dir2;` `dir` has the same value and the pointer to the `new`ed instance is lost. This is a memory leak. – Scheff's Cat Nov 18 '17 at 07:40
  • I have removed the new and *s. But now there are a runtime error - error: use of deleted function ‘Directory::Directory(const Directory&)’ Directory dir = Directory("alex"); ^ – Alex Lavriv Nov 18 '17 at 07:46
  • 1
    Use of deleted function: You have to define a copy constructor. I'm always not quite sure when the copy constructor is auto-defined when not. But actually it is always better to follow the [rule of 5](https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)). (Hence, I don't know because I don't need to know.) – Scheff's Cat Nov 18 '17 at 08:02
  • It might feel tedious to always write "all 5". So, it might be interesting to know about: `Directory() = default;` (forces the auto-creation of default constructor), `Directory(const Directory&) = default;` (forces the auto-creation of default copy constructor) and so on. – Scheff's Cat Nov 18 '17 at 08:07
  • ...and to prevent unintended copying of class instances (when this shouldn't happen) a `Directory(const Directory&) = delete;` can be used to force the "not-auto-creation" of a default copy constructor. – Scheff's Cat Nov 18 '17 at 08:10

2 Answers2

1

Maybe try like this:

#include <iostream>
#include <string>

using namespace std;

class Directory{
public:
       string name;

        Directory() {
            cout << "Constructor 1 was called" <<endl;            
        }

        Directory(string name):name(name) {
            cout << "Constructor 2 was called" <<endl;            
        }

        ~Directory() {
            cout << "Deleting was called" <<endl;
        }

        Directory(const Directory& other){
            cout << "cp cons" <<endl;
        }

        Directory& operator=(const Directory& other){
            cout << "cp assigment" <<endl;
            return *this;
        }

        Directory& operator=(Directory&& other){
            cout << "move assigment" <<endl;
            return *this;
        }
};


int main()
{

    Directory dir = Directory("alex");
    Directory dir2;
    dir2 = dir;

    cout << "done " << dir.name << dir2.name << endl;
};

I changed the code so it doesn't use pointers, add extra constructors (notice the copy constructor) and added some extra printing.

I get this output:

Constructor 2 was called
Constructor 1 was called
cp assigment
done alex
Deleting was called
Deleting was called

From this you can see that your copy assignment is incorrect as it still prints "alex" but I guess you are only interested in the function being called and not what they do.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Thank you for your effort. It really works. I am trying to learn from this example. I don't understand why your code works, and my is not working. The main part is the same, after an edit. – Alex Lavriv Nov 18 '17 at 08:11
  • @AlexLavriv - did you add a copy constructor like I did? – Support Ukraine Nov 18 '17 at 08:13
  • @AlexLavriv - This link may be interesting for you: https://stackoverflow.com/a/9945598/4386427 – Support Ukraine Nov 18 '17 at 08:21
  • I have added it now. And it works. But it does not use it. For some reason the move assignment requires the copy constructor to be presented. It's a really strange behavior. – Alex Lavriv Nov 18 '17 at 08:24
  • @AlexLavriv - there is no move assignment involved. It's an optimization eliding the temporary (i.e. `Directory("alex");`). – Support Ukraine Nov 18 '17 at 08:31
1

I my first comment, I recommended to remove all *s and the new.

Hence the main function becomes:

int main()
{
  Directory dir = Directory("alex");
  Directory dir2;
  dir2 = dir; // <-- fixed, original was: dir = dir2;

  cout<<"done"<<endl;
  return 0; // <-- fixed, return is strictly recommended for every non-void function
}

Compiling...

Error: Something is wrong in Directory dir = Directory("alex"); (usage of deleted copy constructor).

The copy-constructor is used to initialize dir with the temporary instance created by Directory("alex").

This is easy to change:

int main()
{
  Directory dir("alex"); // <-- fixed: direct construction
  Directory dir2;
  dir2 = dir;

  cout<<"done"<<endl;
  return 0;
}

Compiling...

Error: Something is wrong in Directory dir2;.

A yepp. You defined constructor Directory(string name);. This suppresses the auto-creation of the default constructor which would be needed here.

We either could add the default constructor to class Directory:

  Directory() = default;

or we can improve the existing non-default constructor so that it can be used as default constructor as well:

  Directory(string name = string()): name(name) { }

The whole source:

#include <iostream>
#include <string>
using namespace std;

class Directory{

    string name;
public:
        Directory(string name = string()):name(name) {

        }
        ~Directory() {
            cout << "Deleting was called" <<endl;

            }

        Directory& operator=(Directory& other){
            cout << "cp assigment" <<endl;
            return *this;
        }
        Directory& operator=(Directory&& other){
            cout << "move assigment" <<endl;
            return *this;
        }
};

int main() {
    //Directory dir = Directory("alex");
    Directory dir("alex");
    Directory dir2;
    dir2 = dir;

    cout<<"done"<<endl;
    // your code goes here
    return 0;
}

Now, it compiles and works.

Output:

cp assigment
done
Deleting was called
Deleting was called

You can see it live on ideone.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56