move constructor / move assignment

Feb 5, 2021 at 9:42pm
Recently I have been practicing the different types of constructors and assingment operators. I am now doing the move constructor and assignment, and I think I have it somewhat correct, but I can not find any examples that have any class variables apart from the pointer that needs to be moved, so I am not sure if i am doing it correct. Is my move constructor and assignment correct? I am most unsure about the std::move in the assignment, im not sure if this is the correct way of doing it.

When I am testing the program it is running correctly, but ive done things in the past that worked but wasnt put together right, and I want to be learning the correct way. So any help is appreciated.
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
45
46
47
48
49
50
51
52
53
54
55
  #pragma once
#include <iostream>
#include "engine.h"

using std::string;

class vehicle
{
private:
	string* ptr_Name;
	string colour;
	int doors;
	engine Engine;

public:
	//constructor
	vehicle(string P_name, string& P_colour, int& P_doors, engine P_engine) : ptr_Name(new string(P_name)), colour(P_colour), doors(P_doors), Engine(P_engine)  {}
	//destructor
	~vehicle() { delete ptr_Name; }
	//copy constructor
	vehicle(const vehicle& obj) : ptr_Name(new string(obj.getName())), colour(obj.colour), doors(obj.doors), Engine(obj.Engine) {}
	//copy assignment
	vehicle& operator= (const vehicle& obj) 
	{
		if (this != &obj)
		{
			delete ptr_Name;
			ptr_Name = new string(obj.getName());
			colour = obj.getColour();
			doors = obj.getDoors();
			Engine = obj.Engine;
		}	
		return *this;
	}
	//move constructor
	vehicle(vehicle&& obj) : ptr_Name(obj.ptr_Name), colour(std::move(obj.colour)), doors(std::move(obj.doors)), Engine(std::move(obj.Engine))
	{		
		obj.ptr_Name = nullptr;		
	}
	//move assignment
	vehicle& operator= (vehicle&& obj) 
	{
		delete ptr_Name;
		ptr_Name = obj.ptr_Name;
		obj.ptr_Name = nullptr;
		*this = std::move(obj);
		return *this;
	}

	string getName() const;
	string getColour() const;
	int getDoors() const;
	engine getEngine() const;
	void getDetails() const;
};
Feb 6, 2021 at 5:12am
> Is my move constructor and assignment correct? I am most unsure about the std::move in
> the assignment, im not sure if this is the correct way of doing it.

Your move assignment operator would cause an infinite loop.

1
2
3
4
5
6
7
8
9
        //move assignment
	vehicle& operator= (vehicle&& obj) 
	{
		delete ptr_Name;
		ptr_Name = obj.ptr_Name;
		obj.ptr_Name = nullptr;
		*this = std::move(obj); // **** this calls the move assignment operator again
		return *this;
	}


Ideally, the move operations should be non-throwing operations.



> I can not find any examples that have any class variables apart from the pointer that needs to be moved

We could use a member object of a user-defined type (that noisily announces when it is copied, moved etc.) to test out our code. For example:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>

struct noisy_str
{
    noisy_str( const char* cstr ) : str(cstr) { print("constructor") ; }
    noisy_str( std::string str = {} ) : str( std::move(str) ) { print( "constructor" ) ; }

    noisy_str( const noisy_str& that ) : str(that.str) { print( "copy constructor" ) ; }
    noisy_str( noisy_str&& that ) noexcept ( std::is_nothrow_move_constructible<std::string>::value )
        : str( std::move(that.str) ) { print( "move constructor" ) ; }

    noisy_str& operator= ( const noisy_str& that )
    { str = that.str ; print( "copy assignment" ) ; return *this ; }
    noisy_str& operator= ( noisy_str&& that ) noexcept ( std::is_nothrow_move_assignable<std::string>::value )
    {  str = std::move(that.str) ; print( "move assignment" ) ; return *this ; }

    ~noisy_str() { print( "destructor" ) ; }

    operator const std::string& () const noexcept { return str ; }
    operator std::string& () { return str ; }

    std::string str ;

    std::ostream& print( const char* oper ) const
    { return std::cout << "noisy_str::" << oper << '\n' ; }
};

struct vehicle
{
    vehicle( std::string str = "anonymous" ) : name_( std::move(str) ) {}

    vehicle( const vehicle& that ) : name_( that.name_ ) {}

    vehicle( vehicle&& that ) noexcept( std::is_nothrow_move_constructible<noisy_str>::value )
        : name_( std::move(that.name_) ) {}

    vehicle& operator= ( const vehicle& that ) { name_ = that.name_ ; return *this ; }

    vehicle& operator= ( vehicle&& that ) noexcept( std::is_nothrow_move_assignable<noisy_str>::value )
    { name_ = std::move(that.name_) ; return *this ; }

    ~vehicle() = default ;

    const std::string& name() const noexcept { return name_ ; }

    noisy_str name_ ;
};


int main()
{
    {
        std::cout << "construct v: " ;
        vehicle v { "1234" } ;

        std::cout << "\ncopy construct v2: " ;
        vehicle v2(v) ;

        std::cout << "\nmove construct v3: " ;
        vehicle v3( std::move(v2) ) ;

        std::cout << "\ncopy assignment: " ;
        v = v3 ;

        std::cout << "\nmove assignment: " ;
        v3 = std::move(v) ;

        std::cout << "\ndestroy v3, v2, v1\n" ;
    }

    std::cout << "\nconstruct vector of three vehicles\n" ;
    std::vector<vehicle> vec(3) ;

    std::cout << "\nmove the vehicles in the vector\n" ;
    // nothrow_move_constructible, so the vector should use the non-throwing move constructor to move the items
    vec.reserve( vec.capacity() + 1 ) ;

    std::cout << "\ndestroy vector of three vehicles\n" ;
 }

http://coliru.stacked-crooked.com/a/a3454a5aa34113a1
https://rextester.com/UMXG36332
Topic archived. No new replies allowed.