4

这涉及 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(); }

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

在起草该决议时,对该决议发表了以下评论:

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

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

4

1 回答 1

3

考虑:

#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编译)。如果我对输出应该是正确的,那么危险是移动赋值运算符被调用了两次。这对于复制赋值运算符是无害的(尽管可能很昂贵),但对于移动赋值运算符则不然。

于 2013-06-22T17:27:45.900 回答