Dev*_*ull 8 c++ gcc clang c++14
在以下示例中,gcc 7发出警告:
"B"的默认移动分配称为虚拟基础'A'的非平凡移动赋值运算符[-Wvirtual-move-assign]
如果我创建一个std::tuple<B>对象.Clang 5没有报告任何问题.如果vector被删除,问题就会消失Base.例子.
#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
}
Run Code Online (Sandbox Code Playgroud)
为什么会出现std::tuple(并且没有移动分配),如果我需要保持这样的层次结构,那么解决它的正确方法是什么?
警告与此无关tuple,它由移动分配触发B.例如,以下代码生成警告
B b;
B t;
t = std::move(b);
Run Code Online (Sandbox Code Playgroud)
在GCC文档解释了警告的意图
Run Code Online (Sandbox Code Playgroud)-Wno-virtual-move-assign禁止使用非平凡的C++ 11移动赋值运算符从虚拟基础继承警告.这是危险的,因为如果虚拟基地可以沿多个路径到达,则会多次移动,这可能意味着两个对象最终都处于移动状态.如果编写移动赋值运算符以避免从移动的对象移动,则可以禁用此警告.
这是一个演示问题的示例
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();
}
Run Code Online (Sandbox Code Playgroud)
这会产生输出
Base& Base::operator=(Base&&)
Base& Base::operator=(Base&&)
Run Code Online (Sandbox Code Playgroud)
显示单个Base实例被移动分配到两次,一次由每个移动赋值运算符A和B.第二个移动分配来自已经从对象移动,这可能导致第一个移动分配的内容被覆盖.
请注意,clang也会在我的示例中生成一个警告,它可能检测到A示例中的两个路径无法访问,并且没有发出警告.
修复它的方法是为其实现移动赋值运算符,A并且B可以检测Base已移动并省略第二个移动赋值.
| 归档时间: |
|
| 查看次数: |
880 次 |
| 最近记录: |