![](/img/trans.png)
[英]Defaulted move assignment cannot be explicitly noexcept if a member has a non-trivial noexcept assignment operator
[英]Why does gcc warn about calling a non-trivial move assignment operator with std::tuple and virtual inheritance?
在以下示例中,gcc 7發出警告:
“B”的默認移動分配稱為虛擬基礎'A'的非平凡移動賦值運算符[-Wvirtual-move-assign]
如果我創建一個std::tuple<B>
對象。 Clang 5沒有報告任何問題。 如果從Base
刪除vector
,問題就會消失。 例子 。
#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
(並且沒有移動賦值),如果我需要保持這樣的層次結構,修復它的正確方法是什么?
警告與tuple
無關,它由B
的移動分配觸發。 例如,以下代碼生成警告
B b;
B t;
t = std::move(b);
gcc文檔解釋了警告的意圖
-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();
}
這會產生輸出
Base& Base::operator=(Base&&)
Base& Base::operator=(Base&&)
顯示單個Base
實例已移動分配給兩次,一次由A
和B
每個移動賦值運算符分配。 第二個移動分配來自已經從對象移動,這可能導致第一個移動分配的內容被覆蓋。
請注意,clang也會在我的示例中生成警告,它可能會檢測到示例中的兩個路徑無法訪問A
並且不會發出警告。
修復它的方法是為A
和B
實現移動賦值運算符,它可以檢測Base
已被移動並省略第二個移動賦值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.