Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Auto Generates Move Constructor With User Declared Destructor?

According to cppreference and this answer, C++ should not automatically generate a move constructor if there is a user declared destructor. Checking this in practice with Clang, however, I see an auto-generated move constructor. The following code prints "is_move_constructible: 1":

#include <iostream>
#include <type_traits>

struct TestClass
{
  ~TestClass()
  {}
};

int main( int argc, char** argv )
{
  std::cout << "is_move_constructible: " << std::is_move_constructible<TestClass>::value << std::endl;
}

Am I misunderstanding "there is no user-declared destructor" or std::is_move_constructible? I'm compiling with '-std=c++14' and Apple LLVM version 7.0.2 (clang-700.1.81).

like image 913
Christopher Johnson Avatar asked Feb 06 '16 09:02

Christopher Johnson


2 Answers

Types without a move constructor, but with a copy constructor that accepts const T& arguments, satisfy std::is_move_constructible and implicitly-declared copy constructor has the form T::T(const T&).

If implicitly-declared copy constructor is deleted, std::is_move_constructible is not satisfied as below.

#include <iostream>
#include <type_traits>

struct TestClass
{
  ~TestClass() {}
  TestClass(const TestClass&) = delete;
};

int main( int argc, char** argv )
{
  std::cout << "is_move_constructible: " << std::is_move_constructible<TestClass>::value << std::endl;
}
like image 145
Alper Avatar answered Sep 18 '22 11:09

Alper


For C++11 code, the accepted answer by @Alper is fine. But to make your code future-proof, note that as of Clang 3.7 (no idea which Apple version that corresponds to, sure you can find out), using -std=c++1z -Wdeprecated will generate the following

warning: definition of implicit copy constructor for 'TestClass' is deprecated because it has a user-declared destructor [-Wdeprecated]
  ~TestClass()
  ^

Live Example

The relevant part of the draft C++1z Standard N4567 is

12.8 Copying and moving class objects [class.copy]

7 If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.

Deprecated means that a future Standard may stop generating an implicit copy constructor in case of a user-declared destructor. It's best practice to change your code today to not rely on deprecated behavior (i.e. in this case, making the copy-behavior of your class explicit).

like image 37
TemplateRex Avatar answered Sep 22 '22 11:09

TemplateRex