簡體   English   中英

GCC C++11 刪除移動可分配類的復制分配會阻止 std::sort 編譯?

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

我正在嘗試對實現移動賦值運算符的類向量進行排序。 此代碼在 Microsoft 和 Intel C++ 中運行良好。 在 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

在 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;
}

聲明移動構造函數或移動賦值運算符會刪除默認的復制/移動構造函數(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);
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

要解決這個問題:

您需要一個可移動構造的類,您可以通過is_move_constructible對其進行is_move_constructiblestd::sort需要第一個。 放置一個移動構造函數以使其可移動構造。

您至少需要移動賦值或復制賦值之一進行賦值,並且至少需要復制構造函數或移動構造函數之一進行構造。

雖然您的班級名稱是MoveOnly ,但我認為選擇 move-assignment 和 move-constructor 是合理的。 所以,這段代碼足以編譯:

class MoveOnly {

    ...

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

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

我在你的代碼中添加了一些東西,這很好用:

#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:使用 const r-value 引用是一種無稽之談,因為 rvalue 引用的主要目的是移動對象而不是復制它們。 移動對象的狀態意味着修改。 所以沒有常量

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM