A vector of user-defined type

Hi all,

Please consider this 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "C:\Users\...\std_lib_facilities.h"
using namespace std;

class A
{
public:
    //Constructor
    explicit A(size_t length) : mLength(length), mData(new int[length])
    {
        cout << "A(size_t). length = "
            << mLength << "." << endl;
    }

    // Destructor
    ~A()
    {
        cout << "~A(). length = " << mLength << ".";

        if (mData != nullptr) {
            cout << "Deleting resource.";
            delete[] mData;  // Delete the resource.
        }

        cout << endl;
    }

    // Copy constructor.
    A(const A& other) : mLength(other.mLength), mData(new int[other.mLength])
    {
        cout << "A(const A&). length = "
            << other.mLength << ". Copying resource." << endl;

        copy(other.mData, other.mData + mLength, mData);
    }

    // Copy assignment operator.
    A& operator=(const A& other)
    {
        cout << "operator=(const A&). length = "
            << other.mLength << ". Copying resource." << endl;

        if (this != &other) {
            delete[] mData;  // Free the existing resource.
            mLength = other.mLength;
            mData = new int[mLength];
            copy(other.mData, other.mData + mLength, mData);
        }
        return *this;
    }

    // Move constructor.
    A(A&& other) : mData(nullptr), mLength(0)
    {
        cout << "A(A&&). length = "
            << other.mLength << ". Moving resource.\n";

        mData = other.mData;
        mLength = other.mLength;

        other.mData = nullptr;
        other.mLength = 0;
    }

    // Move assignment operator.
    A& operator=(A&& other) 
    {
        cout << "operator=(A&&). length = "
            << other.mLength << ". Move assignment" << endl;

        if (this != &other) {
            
            delete[] mData; // Free the existing resource.

            mData = other.mData;
            mLength = other.mLength;

            other.mData = nullptr;
            other.mLength = 0;
        }
        return *this;
    }

private:
    size_t mLength; // The length of the resource.
    int* mData;     // The resource.
};

#include <vector>

int main()
{
    vector<A> v;
    v.push_back(A(25));

    cin.get();
    return 0;
}


I get this output:

A(size_t). length = 25.
A(A&&). length = 25. Moving resource.
~A(). length = 0.


This v.push_back(A(25)); in the main() causes a temporary object with the value 25 to be created, so the A's explicit constructor is called.
It then goes to the vector v as the first element. Since the object is temporary, for that movement the move constructor of the class, is called. When the movement is taken place, the destructor is called and it actually does nothing because the length and resource of the temp object is previously 0 and freed.

I have two questions:
1) Is the code fine or does it have any issue?
2) Is what I explained above correct, please?




Last edited on
Code tags: learn them, use them.
http://www.cplusplus.com/articles/jEywvCM9/

You've been here long enough (129 posts) you shouldn't need to be reminded.
Doesn't my code have appropriate tags now!?
For the first time when posted, I simply can't, not as my fault but the website's. No tags work as if they're only icons. And I've also sent messages to admins to work it out. Thus the only remedy is to firstly post it and then when I edit it I can use tags and modify the code properly.
frek wrote:
Doesn't my code have appropriate tags now!?
Looks like your code was derived from this MSDN page:
https://docs.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=vs-2019

1) Is the code fine or does it have any issue?
It appears correct after a brief look.

This class provides no exception safety guarantees. An exception thrown during copy assignment, for example, will result in loss of user data.

Separately from the above, move operations should be noexcept. Otherwise, some containers like std::vector will fall-back to copying elements of type A in order to meet their own exception-safety guarantees. If it exists, swap should be noexcept too.

std::exchange can often be used to simplify move special members.

Avoid std::endl when '\n' is sufficient. endl flushes the stream buffer to its output device, which is a very expensive operation on many systems.

The statement
delete nullptr;
has no effect, so no test for nullptr should be made before calling delete.

The move constructor's member initializer list is out-of-order with respect to the data members. This isn't an error in this case, but a decent compiler will complain about it.

2) Is what I explained above correct, please?
Yes, AFAICT
Last edited on
Topic archived. No new replies allowed.