gpt4 book ai didi

c++ - 对于同一层次结构中的对象,-Wreturn-std-move clang 警告是否正确?

转载 作者:太空狗 更新时间:2023-10-29 19:51:03 25 4
gpt4 key购买 nike

考虑以下简单代码:

struct Base
{
Base() = default;
Base(const Base&);
Base(Base&&);
};

struct Derived : Base { };

Base foo()
{
Derived derived;
return derived;
}

clang 8.0.0 gives a warning -Wreturn-std-move在上面:

prog.cc:21:10: warning: local variable 'derived' will be copied despite being returned by name [-Wreturn-std-move]
return derived;
^~~~~~~
prog.cc:21:10: note: call 'std::move' explicitly to avoid copying
return derived;
^~~~~~~
std::move(derived)

但是如果在这里调用 std::move 代码的行为可能会改变,因为 Derived 对象的 Base 子对象将是在调用 Derived 对象的析构函数之前 move ,最后一个代码的行为会有所不同。

例如看the code (compiled with the -Wno-return-std-move flag) :

#include <iostream>
#include <iomanip>

struct Base
{
bool flag{false};

Base()
{
std::cout << "Base construction" << std::endl;
}

Base(const bool flag) : flag{flag}
{
}

Base(const Base&)
{
std::cout << "Base copy" << std::endl;
}

Base(Base&& otherBase)
: flag{otherBase.flag}
{
std::cout << "Base move" << std::endl;
otherBase.flag = false;
}

~Base()
{
std::cout << "Base destruction" << std::endl;
}
};

struct Derived : Base
{
Derived()
{
std::cout << "Derived construction" << std::endl;
}

Derived(const bool flag) : Base{flag}
{
}

Derived(const Derived&):Base()
{
std::cout << "Derived copy" << std::endl;
}

Derived(Derived&&)
{
std::cout << "Derived move" << std::endl;
}

~Derived()
{
std::cout << "Derived destruction" << std::endl;
std::cout << "Flag: " << flag << std::endl;
}
};

Base foo_copy()
{
std::cout << "foo_copy" << std::endl;
Derived derived{true};
return derived;
}

Base foo_move()
{
std::cout << "foo_move" << std::endl;
Derived derived{true};
return std::move(derived);
}

int main()
{
std::cout << std::boolalpha;
(void)foo_copy();
std::cout << std::endl;
(void)foo_move();
}

它的输出:

foo_copy
Base copy
Derived destruction
Flag: true
Base destruction
Base destruction

foo_move
Base move
Derived destruction
Flag: false
Base destruction
Base destruction

最佳答案

Clang 的警告当然是正确的。由于 derived 的类型不同于函数的返回类型,因此在语句 return derived; 中,编译器必须将 derived 视为左值, 并且会出现一个拷贝。并且可以通过编写 return std::move(derived); 来避免此拷贝,使其显式成为右值。警告不会告诉您是否应该这样做。它只是告诉您您正在做的事情的后果,以及使用 std::move 的后果,并让您自己下定决心。

您担心 Derived 的析构函数可能会在 Base 状态被 move 后访问它,这可能会导致错误。如果确实出现此类错误,那是因为 Derived 的作者犯了错误,而不是因为用户不应该 move Base 子对象。此类错误可以通过与其他错误相同的方式被发现,并报告给 Derived 的作者。

我为什么这么说?因为当作者使 Base 成为 Derivedpublic 基类时,他们向用户 promise 他们有权使用完整的 Base 接口(interface),每当与 Derived 对象交互时,包括从它 move 。因此,Derived 的所有成员函数必须准备好处理这样一个事实,即用户可能以 Base 的任何方式修改了 Base 子对象的接口(interface)允许。如果不需要,则可以将 Base 设为 Derived 的私有(private)基类,或私有(private)数据成员,而不是公共(public)基类。

关于c++ - 对于同一层次结构中的对象,-Wreturn-std-move clang 警告是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55924330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com