如果对象具有用户定义/声明的析构函数,为什么编译器将static_cast添加到 const rvalue ref

Why did compiler add static_cast to const rvalue ref if an object has a user defined/declared destructor

提问人:cpp 提问时间:11/8/2023 最后编辑:cpp 更新时间:11/8/2023 访问量:87

问:

以下示例所示

struct Apple  {
  ~Apple() {};
};

int main()
{
    Apple a1;
    Apple a2 = std::move(a1);
}

例子

struct Apple  {
  ~Apple() = default;
};

int main()
{
    Apple a1;
    Apple a2 = std::move(a1);
}

由编译器完成以下转换

struct Apple
{
  inline ~Apple() /* noexcept */ = default;
  // inline constexpr Apple() noexcept = default;
  // inline constexpr Apple(const Apple &) noexcept = default;
};



int main()
{
  Apple a1;
  Apple a2 = Apple(static_cast<const Apple &&>(std::move(a1)));
  return 0;
}

编译器添加于static_cast<const Apple &&>

Apple a2 = Apple(static_cast<const Apple &&>(std::move(a1)));

如果有用户定义/声明的析构函数。 根据示例,情况并非如此

struct Apple  {
};

int main()
{
    Apple a1;
    Apple a2 = std::move(a1);
}

其中编译器转换后的代码片段是

struct Apple
{
  // inline constexpr Apple() noexcept = default;
  // inline constexpr Apple(Apple &&) noexcept = default;
};



int main()
{
  Apple a1;
  Apple a2 = Apple(std::move(a1));
  return 0;
}

如果用户未定义/声明析构函数。

为什么会这样?

PS 人们倾向于认为这是因为使用用户声明/定义的析构函数,编译器只会隐式生成复制构造函数,而不会移动构造函数。这是正确的。 但即使只有复制构造函数而没有移动构造函数,const Apple& 也能够绑定到 rvalue ref 并且static_cast<const Apple&> 对于代码编译不是必需的,对吗?

C++ C++11 移动 右值引用值 类别

评论

2赞 Eljay 11/8/2023
由于前两个没有移动构造函数,因此无法对其进行移动构造,因为它们都声明了析构函数。提供移动构造函数,它们可以被移动构造。第三个编译器可以合成移动构造函数,因为它具有隐式合成的析构函数。Apple(Apple&&)
3赞 heap underrun 11/8/2023
这里解释一下:根据特殊成员备忘单,如果用户声明了析构函数,编译器将不会声明移动构造函数。
0赞 yeputons 11/8/2023
旁注:编译器可以自由地做任何它想做的事情,只要结果做原来做的任何事情。因此,“为什么那个特定的工具认为编译器 X 做了 Y”这个问题很可能用“因为工具/编译器这么认为”或“因为 Y 便于 X 的实现”来回答。

答: 暂无答案