背后的原因:局部变量 'derived' 将被复制,尽管按名称返回

Reasoning behind: local variable 'derived' will be copied despite being returned by name

这是 Is -Wreturn-std-move clang warning correct in case of objects in the same hierarchy? 的跟进,因为我不明白某些特定情况下的推理。

struct Field {
  Field();
//  Field(const Field&); // (a)
  int a[1000000];
};

struct Base
{
  Base();
//  Base(const Base&); // (b)
//  Base(Base&&); // (c)
  Field f;
};

struct Derived : Base { };

Base foo()
{
  Derived derived;
  return derived;
}
  1. 上面的代码编译得很好。我明白,std::move 不会做任何不同的事情。
  2. 取消注释 (a),您会收到警告。为什么?我相信 std::move 仍然不会做任何不同的事情。
  3. 取消注释 (b)(保留 (a) 未注释),再次正常工作。它与#2 有何不同?
  4. 取消注释 (c)(保留 (a) 和 (b) 未注释),再次显示警告。这是有道理的,std::move 可以为我们节省一份副本。
  5. 有 foo return 派生,再次正常工作。它与#4 有何不同?

如 link 答案和 cppreference

中所述

我们首先将 derived 视为右值,如果它不是 select XXX(/*const*/Derived&&)(直到 C++20),那么我们将其重新视为左值。

所以只要没有Base(Derived&&),就复制一份

虽然我没有找到警告的全部逻辑。1. 2. 3. 应该被视为相同的 IMO(没有当前等效的警告,或者警告以备将来证明)。

对于 1.

复制和移动构造函数由编译器生成。
复制或移动最后得到相同的结果。

2.

Field 不再生成移动构造函数,使整个链复制而不是移动。
复制或移动最后得到相同的结果。

3.

Base不再生成移动构造函数,从头开始复制。
复制或移动最后得到相同的结果。

对于 4.

Base 具有复制和移动构造函数。
复制或移动给出不同的结果。

为 5。

我们现在有匹配项 XXX(Derived&&) (XXX=Derieved),因此没有完成复制。