gpt4 book ai didi

c++ - 为什么 gcc 警告使用 std::tuple 和虚拟继承调用非平凡的移动赋值运算符?

转载 作者:可可西里 更新时间:2023-11-01 17:39:57 24 4
gpt4 key购买 nike

在下面的例子中,gcc 7 给出了警告:

defaulted move assignment for 'B' calls a non-trivial move assignment operator for virtual base 'A' [-Wvirtual-move-assign]

如果我创建一个 std::tuple<B>目的。 Clang 5 没有报告任何问题。如果vector,问题也会消失从 Base 中删除. Example .

#include <tuple>
#include <vector>

class Base
{
public:
virtual ~Base();
std::vector<int> v;
};

class A : public Base
{
};

class B : public virtual A
{
};

int main()
{
B *b = new B;
B another{*b}; // <<<--- this compiles
std::tuple<B> t; // <<<--- gives warning
}

为什么会在 std::tuple 存在的情况下发生? (并且没有移动分配)如果我需要保持这样的层次结构,修复它的正确方法是什么?

最佳答案

警告与元组无关,它是由B的移动赋值触发的。例如,以下代码生成警告

B b;
B t;
t = std::move(b);

gcc documentation解释警告的意图

-Wno-virtual-move-assign

Suppress warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator. This is dangerous because if the virtual base is reachable along more than one path, it is moved multiple times, which can mean both objects end up in the moved-from state. If the move assignment operator is written to avoid moving from a moved-from object, this warning can be disabled.

这是一个 example说明问题

struct Base
{
Base() = default;
Base& operator=(Base&&)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
return *this;
}
};

struct A : virtual Base {};

struct B : virtual Base {};

struct C : A, B {};

int main()
{
C c;
c = C();
}

这会产生输出

Base& Base::operator=(Base&&)
Base& Base::operator=(Base&&)

显示单个 Base 实例被移动赋值了两次,一次是通过 AB 的每个移动赋值运算符。第二个移动分配来自一个已经移动的对象,这可能会导致第一个移动分配的内容被覆盖。

请注意,在我的示例中,clang 也会生成警告,它可能检测到 A 在您的示例中无法通过两条路径访问,因此不会发出警告。

修复它的方法是为 AB 实现移动赋值运算符,它可以检测到 Base 已被移动并省略第二次移动任务。

关于c++ - 为什么 gcc 警告使用 std::tuple 和虚拟继承调用非平凡的移动赋值运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46599222/

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