Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it necessary to implement move constructor for a class without dynamic resources?

I have a container class like the following. As you can see that all the resources that the class use is allocated statically. There are no dynamically allocated resources in the class. Does such a class need a move constructor or move assignment operator?

template<class T, std::size_t SIZE>
class Stack{
    static_assert(SIZE != 0, "Stack capacity cannot be zero!");

public:
    /*** Constructors and Destructor ***/
    Stack() = default;             // Default constructor
    Stack(const Stack& copyStack); // Copy constructor
    ~Stack();                      // Destructor

    /*** Member Methods ***/
    /* .... */
    void swap(Stack& swapStack);

private:
    /*** Members ***/
    std::size_t idxTop{0};   // Index after the top element
    T data[SIZE];            // Contained data
};

For the ones who would like to try it out with the actual implementation:

  • Source code of Template Stack Container
  • Executable code on GodBolt
like image 242
Caglayan DOKME Avatar asked Jul 17 '21 09:07

Caglayan DOKME


People also ask

Why do we need move constructor?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.

Is move constructor automatically generated?

No move constructor is automatically generated.

What is the point of a move constructor C++?

A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy. An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.

What is the difference between move constructor and copy constructor?

If any constructor is being called, it means a new object is being created in memory. So, the only difference between a copy constructor and a move constructor is whether the source object that is passed to the constructor will have its member fields copied or moved into the new object.


3 Answers

Here's the thing. Your class isn't movable, because it doesn't have dynamically allocated resources. But the resources it contains might. A T, for instance, might be a std::vector in some instantiation. That can surely be moved, so you have to make sure that by providing a copy constructor (you forgot to = default; it btw), the compiler doesn't accidentally disable the default move constructor.

Now, you should be careful about the default move constructor in your case. The problem is that you have an array as a member, and the default move constructor just moves the elements of the array one by one.

Except what happens when the move constructor of one of them throws? You end up with half of the elements moved, and some still in the old array because an exception was thrown. That's no good. Take a look at std::move_if_noexcept and perhaps try implementing the move constructor to fix this.

like image 130
super Avatar answered Nov 15 '22 07:11

super


What exactly do you mean by need? I guess that you mean whether you need to write them for you class to stay moveable.

If you have an example like this:

#include <cstdint>
#include <utility>
class Foo
{
  private: 
  std::size_t idxTop{0};
  int data[4];
};

int main()
{
  Foo f = Foo(); // Default ctor
  Foo x = Foo(f); // Copy ctor
  x = f; // Copy assignment
  x = std::move(f); // Move assignment
  Foo y = std::move(f); // Move ctor
}

The compiler will add

  inline constexpr Foo() noexcept = default;
  inline constexpr Foo(const Foo &) noexcept = default;
  inline constexpr Foo(Foo &&) noexcept = default;
  inline constexpr Foo & operator=(const Foo &) noexcept = default;
  inline constexpr Foo & operator=(Foo &&) noexcept = default;

to the class's definition. I.e the class can be copied, moved freely as is shown in the main.

But - that's maybe what prompted your question - if you write a custom {copy con,des}structor for a class as you have done, the compiler will not put the defaulted definitions there. Why? Because by writing custom ones, you sent a signal that your class in some way special and default implementations would most likely not do the right thing.

So, your class is not moveable but remains copyable and copies will be used instead of move operations when required - e.g. the last two lines in my example.

I would suggest that whenever you customize one of those 5 functions, you define all of them, use default or delete if they suffice.

You can find more information about the default rules in the rule of three/five/zero.

like image 43
Quimby Avatar answered Nov 15 '22 08:11

Quimby


No, your class does not need a move-ctor or move-assignment-operator.

You can't move static arrays, you can only copy their content. So a potential move-ctor would do the same as the copy-ctor. The same goes for assignment operators.

like image 22
churill Avatar answered Nov 15 '22 07:11

churill