只需添加什么都不做的析构函数会导致编译错误(大约 std::move),为什么?
just add destructor that do nothing can cause compile error (around std::move), why?
在学习std::move
的过程中,我发现了一个奇怪的问题。
如果我只添加一个对完美程序什么都不做的析构函数,我会得到一个编译错误。
#include <iostream>
using namespace std;
class M {
public:
int database = 0;
M &operator=(M &&other) {
this->database = other.database;
other.database = 0;
return *this;
}
M(M &&other) { *this = std::move(other); }
M(M &m) = default;
M() = default;
~M() { /* free db */ }
};
class B {
public:
M shouldMove;
//~B(){} //<--- ## Adding this line will cause compile error. ##
};
int main() {
B b;
B b2 = std::move(b); //## error at this line if the above line is added
return 0;
}
实时代码:https://ideone.com/UTR9ob
错误是invalid initialization of non-const reference of type 'B&' from an rvalue of type 'std::remove_reference<B&>::type {aka B}'
。
问题:
- (1) 哪些 C++ 语法规则强制执行此操作?换句话说,错误是什么意思?
- (2) 如果我想添加几乎什么都不做的析构函数(例如只打印调试日志)到
B
,我真的必须遵循 五法则 而不是?如果没有,如何编译?在我看来,仅仅因为遵循五法则就太乏味和肮脏了。
我认为零规则只是一个很好的实践。
但是,从这个例子来看,我觉得这是一个硬性规定,如果违反了,我会得到编译错误。
隐式声明的移动构造函数仅在 class 没有用户声明的析构函数时出现。因此 2. 的答案是肯定的。
1. 的答案是,这是硬性规定,可以在标准的 12.8 第 9 段中找到:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared
as defaulted if and only if
- X does not have a user-declared copy constructor,
- X does not have a user-declared copy assignment operator,
- X does not have a user-declared move assignment operator,
- X does not have a user-declared destructor, and
- the move constructor would not be implicitly defined as deleted.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that
otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]
将此设置为 运行 的最佳方法是使用智能指针之类的东西,即一个基 class 或定义所有五个特殊成员的成员(以及很少的其他成员) ) 这样您就不必这样做了。在这种情况下,相当于 std::unique_pointer
的整数句柄应该可以正常工作。但是,请记住,数据库和文件一样,在关闭时可能会出错,因此标准的非抛出析构函数语义并不涵盖所有情况。
在学习std::move
的过程中,我发现了一个奇怪的问题。
如果我只添加一个对完美程序什么都不做的析构函数,我会得到一个编译错误。
#include <iostream>
using namespace std;
class M {
public:
int database = 0;
M &operator=(M &&other) {
this->database = other.database;
other.database = 0;
return *this;
}
M(M &&other) { *this = std::move(other); }
M(M &m) = default;
M() = default;
~M() { /* free db */ }
};
class B {
public:
M shouldMove;
//~B(){} //<--- ## Adding this line will cause compile error. ##
};
int main() {
B b;
B b2 = std::move(b); //## error at this line if the above line is added
return 0;
}
实时代码:https://ideone.com/UTR9ob
错误是invalid initialization of non-const reference of type 'B&' from an rvalue of type 'std::remove_reference<B&>::type {aka B}'
。
问题:
- (1) 哪些 C++ 语法规则强制执行此操作?换句话说,错误是什么意思?
- (2) 如果我想添加几乎什么都不做的析构函数(例如只打印调试日志)到
B
,我真的必须遵循 五法则 而不是?如果没有,如何编译?在我看来,仅仅因为遵循五法则就太乏味和肮脏了。
我认为零规则只是一个很好的实践。
但是,从这个例子来看,我觉得这是一个硬性规定,如果违反了,我会得到编译错误。
隐式声明的移动构造函数仅在 class 没有用户声明的析构函数时出现。因此 2. 的答案是肯定的。
1. 的答案是,这是硬性规定,可以在标准的 12.8 第 9 段中找到:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
- X does not have a user-declared copy constructor,
- X does not have a user-declared copy assignment operator,
- X does not have a user-declared move assignment operator,
- X does not have a user-declared destructor, and
- the move constructor would not be implicitly defined as deleted.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]
将此设置为 运行 的最佳方法是使用智能指针之类的东西,即一个基 class 或定义所有五个特殊成员的成员(以及很少的其他成员) ) 这样您就不必这样做了。在这种情况下,相当于 std::unique_pointer
的整数句柄应该可以正常工作。但是,请记住,数据库和文件一样,在关闭时可能会出错,因此标准的非抛出析构函数语义并不涵盖所有情况。