【问题标题】:Danger with virtual base move assignment operators when they are now allowed to be used?现在允许使用虚拟基础移动分配运算符时存在危险吗?
【发布时间】:2013-06-19 15:00:40
【问题描述】:

这涉及 C++ 问题 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1402 的解决。总结:

template<typename T>
struct wrap
{
   wrap() = default;

   wrap(wrap&&) = default;
   wrap(const wrap&) = default;

   T t;
};

struct S {
   S(){}
   S(const S&){}
   S(S&&){}
};

typedef wrap<const S> W;

// Error, defaulted move constructor of "wrap<const S>" is deleted!
W get() { return W(); }

(问题是我们得到了这个 sn-p 的错误,即使编译器可以简单地使用“S”的复制构造函数,就像用户显式编写“wrap”的移动构造函数时那样。该问题已解决,在重载决议期间忽略已删除的移动构造函数(和赋值运算符),因此可以根据需要使用上面的复制构造函数。)

当分辨率was drafted, the following comment was made关于这个分辨率:

相对于复制的隐式/默认移动操作没有其他限制。这意味着虚拟基础中的移动赋值是危险的(编译器可能应该警告)[...] 但是我们在 Batavia 中决定我们不会保留所有 C++03 代码以防止隐式移动操作,我认为此分辨率提供了显着的性能优势。

有人可以描述一下虚拟基地移动分配运算符的问题吗?

【问题讨论】:

  • 它可能不止一次发生?这不只是分配虚拟基地的一般问题的一个方面吗?
  • @KerrekSB 啊我不知道这是可能的。虽然我仍然没有很清楚地看到这个问题。如果您能澄清什么时候会出现问题,我会很高兴。
  • 这在 gcc 4.7.3 下编译正常,带有 -std=c++11 -Wall;您使用的是哪个编译器?会不会仅仅是对“用户提供”与“用户定义”的误解导致的编译器缺陷?
  • @kfsone 我认为 DR 负责拒绝的规则是“类型必须具有移动构造函数”。从字面上解释,测试用例确实有效。但实际上,预期的解释出现了“构造函数的重载解析必须选择一个移动构造函数”。因此,虽然“const S”有一个移动构造函数,以“const S”作为参数进行重载解析,但我们得到了复制构造函数作为结果。我不认为 GCC 会按字面意思解释它(鉴于 DR 的决议是由 GCC 的维护者起草的)。也许 GCC 只是已经实施了解决方案。

标签: c++ c++11 c++14 deleted-functions


【解决方案1】:

考虑:

#include <iostream>

struct A
{
    A() = default;
    A(const A&) = default;
    A(A&&) = default;
    A& operator=(const A&) {std::cout << "operator=(const A&)\n"; return *this;}
    A& operator=(A&&) {std::cout << "operator=(A&&)\n"; return *this;}
};

struct B
    : virtual public A
{
};

struct C
    : virtual public A
{
};

struct D
    : public B,
      public C
{
};

int
main()
{
    D d1, d2;
    d1 = std::move(d2);
}

我相信这个程序应该输出:

operator=(A&&)
operator=(A&&)

对我来说它实际上输出:

operator=(const A&)
operator=(const A&)

但我认为这只是一个 clang 错误(使用 -std=c++1y 编译)。如果我对输出应该是正确的,那么危险是移动赋值运算符被调用了两次。这对于复制赋值运算符是无害的(尽管可能很昂贵),但对于移动赋值运算符则不然。

【讨论】:

  • 确实,gcc 4.8.1 输出“AA&”,而 clang++ 3.3 输出“A&”。
  • 是的,clang 还没有实现 DR1402 的分辨率。当它这样做时,它应该给出你建议的输出,调用虚拟基地的移动赋值运算符两次。
猜你喜欢
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 1970-01-01
  • 2017-02-14
  • 2018-10-17
  • 1970-01-01
相关资源
最近更新 更多