简体   繁体   English

GCC C++11 删除移动可分配类的复制分配会阻止 std::sort 编译?

[英]GCC C++11 deleting copy assignment for move assignable classes prevents std::sort from compiling?

I'm trying to sort a vector of class that implements move assignment operator.我正在尝试对实现移动赋值运算符的类向量进行排序。 This code works fine in Microsoft and Intel C++.此代码在 Microsoft 和 Intel C++ 中运行良好。 In GCC 4.8.1, the copy constructor is deleted and seems causing problem.在 GCC 4.8.1 中,复制构造函数被删除并且似乎引起了问题。

c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_algo.h:2164:11: error: use of deleted function 'constexpr MoveOnly::MoveOnly(const MoveOnly&)'
__val = _GLIBCXX_MOVE(*__i);
        ^
test.cpp:6:11: note: 'constexpr MoveOnly::MoveOnly(const MoveOnly&)' is implicitly declared as deleted because 'MoveOnly' declares a move constructor or move assignment operator

And with help from Matthieu M., this page explained why the copy constructor is deleted.在 Matthieu M. 的帮助下, 本页解释了为什么删除了复制构造函数。

#include <vector>
#include <algorithm>
#include <iostream>
#include <type_traits>

class MoveOnly {

public:
    int data;
    MoveOnly& operator = (const MoveOnly && rhs) {
        data = rhs.data;
        return *this;
    }
    MoveOnly& operator = (const MoveOnly & rhs) {
        data = rhs.data;
        return *this;
    }
    bool operator < (const MoveOnly& j) const {
        return data<j.data;
    }
};

int main() {

    std::cout<<"Is move_assignable:"<<std::is_move_assignable<MoveOnly>::value<<std::endl;
    std::cout<<"Is copy_assignable:"<<std::is_copy_assignable<MoveOnly>::value<<std::endl;
    std::vector<MoveOnly> vMoveOnly;
    //std::sort(vMoveOnly.begin(), vMoveOnly.end());
    return 0;
}

Declaring a move constructor or move assignment operator deletes the default copy/move constructors (IMO due to encourage us to obey rule of five!), on the other hand std::sort needs one of move-construct or copy-construct having this code:声明移动构造函数或移动赋值运算符会删除默认的复制/移动构造函数(IMO 是为了鼓励我们遵守五规则!),另一方面, std::sort需要具有此代码的移动构造或复制构造之一:

    template<typename _RandomAccessIterator>
    void
    __insertion_sort(_RandomAccessIterator __first,
             _RandomAccessIterator __last)
    {
      if (__first == __last)
    return;

    for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
    {
      if (*__i < *__first)
        {
          typename iterator_traits<_RandomAccessIterator>::value_type
        __val = _GLIBCXX_MOVE(*__i);
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To solve the issue:要解决这个问题:

You need a class which is move-constructable and you can test it by is_move_constructible , std::sort needs first one.您需要一个可移动构造的类,您可以通过is_move_constructible对其进行is_move_constructiblestd::sort需要第一个。 Put a move-constructor to make it move-constructable.放置一个移动构造函数以使其可移动构造。

You need at least one of move-assignment or copy-assignment for assignment, and at least one of copy-constructor or move-constructor for construction.您至少需要移动赋值或复制赋值之一进行赋值,并且至少需要复制构造函数或移动构造函数之一进行构造。

While you class name is MoveOnly , I think it's reasonable to pick move-assignment and move-constructor.虽然您的班级名称是MoveOnly ,但我认为选择 move-assignment 和 move-constructor 是合理的。 So, this code is enough to compile:所以,这段代码足以编译:

class MoveOnly {

    ...

    MoveOnly(MoveOnly &&m) : data(m.data) {}

    MoveOnly& operator = (const MoveOnly && rhs) { ... }
};

I have add a few things to your code and this works fine :我在你的代码中添加了一些东西,这很好用:

#include <vector>
#include <algorithm>
#include <iostream>
#include <type_traits>

class MoveOnly {

public:
    int data;
        MoveOnly (int i): 
        data (i)
        {}

    MoveOnly (MoveOnly && rhs): 
        data (std::move(rhs.data))
        {}
    MoveOnly (const MoveOnly & rhs)=delete;

    MoveOnly& operator = (MoveOnly && rhs) {
        data = std::move(rhs.data);
        return *this;
    }
    MoveOnly& operator = (const MoveOnly & rhs) {
        data = rhs.data;
        return *this;
    }
    bool operator < (const MoveOnly& j) const {
        return data<j.data;
    }
};

int main() {

    std::cout<<"Is move_assignable:"<<std::is_move_assignable<MoveOnly>::value<<std::endl;
    std::cout<<"Is copy_assignable:"<<std::is_copy_assignable<MoveOnly>::value<<std::endl;
    std::vector<MoveOnly> vMoveOnly;
    vMoveOnly.push_back(MoveOnly(10));
    vMoveOnly.push_back(MoveOnly(666));
    vMoveOnly.push_back(MoveOnly(-100));
    std::sort(vMoveOnly.begin(), vMoveOnly.end());
    for(std::size_t i=0;i<vMoveOnly.size();++i){std::cout<<vMoveOnly[i].data<<std::endl;}
    return 0;
}

PS : using a const r-value reference is kind of nonsense because the main purpose of rvalue references is to to move objects instead of copying them. PS:使用 const r-value 引用是一种无稽之谈,因为 rvalue 引用的主要目的是移动对象而不是复制它们。 And moving the state of an object implies modification.移动对象的状态意味着修改。 So no const所以没有常量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM