为什么使用std :: vector :: push_back的move变体调用被移动项的副本构造函数?

时间:2018-09-20 16:39:48

标签: c++ vector move

有些代码无法编译,因为push_back试图调用MoveOnlyClass中的副本构造函数,该副本构造函数已删除:

function fetchData(params: IProps<true>): Promise<IFoo[]>;
function fetchData(params: IProps<false>): Promise<IBar[]>;
function fetchData<T extends boolean>(params: IProps<T>) {
  return apiService('/user/data', params)
    .then(
      (data: IExternalFoo[] | IExternalBar[]) =>
        params.isExtended
          ? (data as IExternalFoo[]).map(mapExternalFoo)
          : (data as IExternalBar[]).map(mapExternalBar)
    );
}

为什么会这样?向量唯一要调用的当然是move构造函数。将对象移到矢量中的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

删除复制构造函数/副本分配函数也将隐式删除移动构造函数/移动分配函数。如果要使对象可移动但不可复制,则还需要default移动构造函数。

class MoveOnlyClass
{
public:
    MoveOnlyClass() {};
    MoveOnlyClass& operator=(const MoveOnlyClass& other) = delete;
    MoveOnlyClass(const MoveOnlyClass& other) = delete;
    MoveOnlyClass& operator=(MoveOnlyClass&& other) = default;
    MoveOnlyClass(MoveOnlyClass&& other) = default;
};

//Will now compile as you expect
int main()
{
    std::vector<MoveOnlyClass> vec;
    vec.push_back(std::move(MoveOnlyClass()));
}

此外,std::move(T())是多余的;像这样就地构造一个对象将已经使其成为R值,并在不需要时使用std::move可能会阻止某些编译器优化(例如,Copy Ellision)。

答案 1 :(得分:2)

@Xirema的回答密封了代码中有关该问题的内容,并解释了为什么是这种情况。

我只想备份语言规范中的适当摘录,以使事情变得正式。因此,来自[class.copy.ctor¶8]

  

(8)如果类X的定义未明确声明move构造函数,则非显式类将隐式声明为默认当且仅当

     
      
  • (8.1) X没有用户声明的副本构造器
  •   

为此,我们应该添加声明为delete仍在声明。因此,根据此,在您的情况下,我们不会得到隐式声明的move构造器,因为我们已经有一个用户声明的副本构造器

进一步,在[dcl.fct.def.delete¶3]下:

  

一个人可以将某个班级设为不可复制,   复制构造函数和复制赋值运算符和   然后提供move构造函数和move的默认定义   赋值运算符。