【问题标题】:Cannot sort std::vector using lambda with const reference无法使用带有 const 引用的 lambda 对 std::vector 进行排序
【发布时间】:2018-05-04 11:14:48
【问题描述】:

我想根据自定义数据类型对向量进行排序。我跟着Sorting a vector of custom objects 回答。我正在使用 lambda 函数来比较对象。但是我在排序时遇到如下编译器错误:

/usr/include/c++/7/bits/stl_algo.h:1852:错误:无法将“MyData&”类型的非常量左值引用绑定到“std::remove_reference::type {aka MyData”类型的右值}' *__first = _GLIBCXX_MOVE(__val); ^

ma​​in.cpp

#include "mydata.h"
#include <vector>

int main()
{
    std::vector<MyData> tv {MyData(2,21), MyData(3,20), MyData(10,100), MyData(9,20)};

    std::sort(tv.begin(), tv.end(), []( MyData const& lhs, MyData const& rhs ){
         return lhs.get_size() < rhs.get_size();
    });

    return 0;
}

mydata.cpp

#ifndef MYDATA_H
#define MYDATA_H
#include <iostream>
#include <algorithm>

class MyData
{
private:

    int *m_data;
    int m_x;
    size_t m_size;

public:
    MyData(const size_t &size,int const &x):
        m_data(new int[size]),
        m_x(x),
        m_size(size)
    {

        std::fill_n(m_data,m_size, m_x);
        std::cout << *m_data << " ctor" << m_size << std::endl;
    }

    MyData(const MyData& other):
        m_data(new int[other.m_size]),
        m_x(other.m_x),
        m_size(other.m_size)
    {
        std::fill_n(m_data,m_size, m_x);
        std::cout << *m_data << " cctor" << m_size << std::endl;
    }

    MyData& operator=(MyData& other)
    {
        std::cout << *m_data << " cbctor" << m_size << std::endl;
        swap(*this,other);
        std::cout << *m_data << " cactor" << m_size << std::endl;
        return *this;
    }

    ~MyData(){
        std::cout << *m_data << " dtor" << m_size << std::endl;
        delete[] m_data;
    }

    size_t get_size() const{
        return m_size;
    }

    friend void swap(MyData& first, MyData& second){    // (1)
        std::swap(first.m_size, second.m_size);
        std::swap(first.m_x, second.m_x);
        std::swap(first.m_data, second.m_data);
    }

    friend std::ostream& operator<< (std::ostream& stream, const MyData& mydata) {
        stream << *(mydata.m_data) << " " << mydata.m_size << " "<< mydata.m_x;
        return stream;

    }

};

#endif // MYDATA_H

我不明白这个错误。我没有更改引用的值,为什么会出现此错误。 我还阅读了this,但不明白为什么会在这里发生。 谢谢。

【问题讨论】:

  • 您的赋值运算符非常错误。如果你有例如MyData a(...), b(...); 然后a = b 将交换ab,但b 预计不会改变。如果您想在赋值运算符中使用swap,请传递参数按值。应该顺便解决你的问题。
  • 为什么您的赋值运算符尝试将swapother 联系起来?它绝对应该修改rhs
  • 感谢@Someprogrammerdude 将分配更改为MyData&amp; operator=(MyData other) 解决了这个问题。但是我不知道在这种情况下使用交换是否最好。我关注了一些博客,他们说使用交换将使赋值运算符异常免费。
  • 您应该将m_data 设为vector&lt;int&gt;。赋值运算符应该包含一个测试 this == &amp;other 在自赋值的情况下什么都不做。

标签: c++ algorithm lambda lvalue


【解决方案1】:

可以有某种类型的声明复制赋值运算符。

  1. 当可以使用复制和交换习语时,这是复制赋值运算符的典型声明:

    MyData& operator=(MyData other);
    
  2. 这是复制赋值运算符的典型声明,当 无法使用复制和交换习语(不可交换类型或降级 性能):

    MyData& operator=(const MyData& other);
    

所以要在您的实现中使用交换,您可以将复制赋值运算符声明为MyData&amp; operator=(MyData other);

【讨论】:

    【解决方案2】:

    你应该像这样修改你的代码:

    #include <iostream>
    #include <fstream>
    #include <thread>
    #include <atomic>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    class MyData
    {
    private:
    
        int *m_data;
        int m_x;
        size_t m_size;
    
    public:
        MyData(const size_t &size, int const &x) :
            m_data(new int[size]),
            m_x(x),
            m_size(size)
        {
    
            std::fill_n(m_data, m_size, m_x);
            std::cout << *m_data << " ctor" << m_size << std::endl;
        }
    
        MyData(const MyData& other) :
            m_data(new int[other.m_size]),
            m_x(other.m_x),
            m_size(other.m_size)
        {
            std::fill_n(m_data, m_size, m_x);
            std::cout << *m_data << " cctor" << m_size << std::endl;
        }
    
        MyData& operator=(const MyData& other)
        {
            std::cout << *m_data << " cbctor" << m_size << std::endl;
            //swap(*this, other);
    
            if (this != &other)
            {
                this->m_data = new int[other.m_size];
                for (size_t i = 0; i < other.m_size; ++i)
                {
                    this->m_data[i] = other.m_data[i];
                }
                this->m_x = other.m_x;
                this->m_size = other.m_size;
            }
            std::cout << *m_data << " cactor" << m_size << std::endl;
            return *this;
        }
    
        ~MyData() {
            std::cout << *m_data << " dtor" << m_size << std::endl;
            delete[] m_data;
        }
    
        size_t get_size() const {
            return m_size;
        }
    
        friend void swap(MyData& first, MyData& second) {    // (1)
            std::swap(first.m_size, second.m_size);
            std::swap(first.m_x, second.m_x);
            std::swap(first.m_data, second.m_data);
        }
    
        friend std::ostream& operator<< (std::ostream& stream, const MyData& mydata) {
            stream << *(mydata.m_data) << " " << mydata.m_size << " " << mydata.m_x;
            return stream;
    
        }
    
    };
    
    int main()
    {
        std::vector<MyData> tv{ MyData(2,21), MyData(3,20), MyData(10,100), MyData(9,20) };
    
        std::sort(tv.begin(), tv.end(), [](MyData const& lhs, MyData const& rhs) {
            return lhs.get_size() < rhs.get_size();
        });
        std::system("pause");
        return 0;
    }
    

    【讨论】:

    • 不要this 那样修改你的代码。此代码中的赋值运算符是内存泄漏的秘诀。声明 this-&gt;m_data = new int[other.m_size]; 孤立(并因此泄漏)this-&gt;m_data 指向函数入口的任何原始数据。
    • 这不是异常安全的。
    • 我没有故意让它异常安全。我刚刚修复了编译问题
    • 一个空白的源文件也可以解决编译问题,但它没有用。
    猜你喜欢
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    • 2010-09-19
    • 2021-02-26
    • 1970-01-01
    • 2016-10-22
    • 2019-03-05
    • 2021-10-28
    相关资源
    最近更新 更多